| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- #include "Library/ForInObjectEnumerator.h"
- #pragma prefast(push)
- #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...")
- static const IR::BailOutKind c_debuggerBailOutKindForCall =
- IR::BailOutForceByFlag | IR::BailOutStackFrameBase | IR::BailOutBreakPointInFunction | IR::BailOutLocalValueChanged | IR::BailOutIgnoreException | IR::BailOutStep;
- static const IR::BailOutKind c_debuggerBaseBailOutKindForHelper = IR::BailOutIgnoreException | IR::BailOutForceByFlag;
- #pragma prefast(pop)
- uint
- IRBuilder::AddStatementBoundary(uint statementIndex, uint offset)
- {
- // Under debugger we use full stmt map, so that we know exactly start and end of each user stmt.
- // We insert additional instrs in between statements, such as ProfiledLoopStart, for these bytecode reader acts as
- // there is "unknown" stmt boundary with statementIndex == -1. Don't add stmt boundary for that as later
- // it may cause issues, e.g. see WinBlue 218307.
- if (!(statementIndex == Js::Constants::NoStatementIndex && this->m_func->IsJitInDebugMode()))
- {
- IR::PragmaInstr* pragmaInstr = IR::PragmaInstr::New(Js::OpCode::StatementBoundary, statementIndex, m_func);
- this->AddInstr(pragmaInstr, offset);
- }
- #ifdef BAILOUT_INJECTION
- if (!this->m_func->IsOOPJIT())
- {
- // Don't inject bailout if the function have trys
- if (!this->m_func->GetTopFunc()->HasTry() && (statementIndex != Js::Constants::NoStatementIndex))
- {
- if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutFlag) && !this->m_func->GetJITFunctionBody()->IsLibraryCode())
- {
- ULONG line;
- LONG col;
- // Since we're on a separate thread, don't allow the line cache to be allocated in the Recycler.
- if (((Js::FunctionBody*)m_func->GetJITFunctionBody()->GetAddr())->GetLineCharOffset(this->m_jnReader.GetCurrentOffset(), &line, &col, false /*canAllocateLineCache*/))
- {
- line++;
- if (Js::Configuration::Global.flags.BailOut.Contains(line, (uint32)col) || Js::Configuration::Global.flags.BailOut.Contains(line, (uint32)-1))
- {
- this->InjectBailOut(offset);
- }
- }
- }
- else if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutAtEveryLineFlag))
- {
- this->InjectBailOut(offset);
- }
- }
- }
- #endif
- return m_statementReader.MoveNextStatementBoundary();
- }
- // Add conditional bailout for breaking into interpreter debug thunk - for fast F12.
- void
- IRBuilder::InsertBailOutForDebugger(uint byteCodeOffset, IR::BailOutKind kind, IR::Instr* insertBeforeInstr /* default nullptr */)
- {
- Assert(m_func->IsJitInDebugMode());
- Assert(byteCodeOffset != Js::Constants::NoByteCodeOffset);
- BailOutInfo * bailOutInfo = JitAnew(m_func->m_alloc, BailOutInfo, byteCodeOffset, m_func);
- IR::BailOutInstr * instr = IR::BailOutInstr::New(Js::OpCode::BailForDebugger, kind, bailOutInfo, bailOutInfo->bailOutFunc);
- if (insertBeforeInstr)
- {
- InsertInstr(instr, insertBeforeInstr);
- }
- else
- {
- this->AddInstr(instr, m_lastInstr->GetByteCodeOffset());
- }
- }
- bool
- IRBuilder::DoBailOnNoProfile()
- {
- if (PHASE_OFF(Js::BailOnNoProfilePhase, this->m_func->GetTopFunc()))
- {
- return false;
- }
- Func *const topFunc = m_func->GetTopFunc();
- if(topFunc->GetWorkItem()->GetProfiledIterations() == 0)
- {
- // The top function has not been profiled yet. Some switch must have been used to force jitting. This is not a
- // real-world case, but for the purpose of testing the JIT, it's beneficial to generate code in unprofiled paths.
- return false;
- }
- if (m_func->HasProfileInfo() && m_func->GetReadOnlyProfileInfo()->IsNoProfileBailoutsDisabled())
- {
- return false;
- }
- if (!m_func->DoGlobOpt())
- {
- return false;
- }
- #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
- if (this->m_func->GetTopFunc() != this->m_func && Js::Configuration::Global.flags.IsEnabled(Js::ForceJITLoopBodyFlag))
- {
- // No profile data for loop bodies with -force...
- return false;
- }
- #endif
- if (!this->m_func->HasProfileInfo())
- {
- return false;
- }
- return true;
- }
- void
- IRBuilder::InsertBailOnNoProfile(uint offset)
- {
- Assert(DoBailOnNoProfile());
- if (this->callTreeHasSomeProfileInfo)
- {
- return;
- }
- IR::Instr *startCall = nullptr;
- int count = 0;
- FOREACH_SLIST_ENTRY(IR::Instr *, argInstr, this->m_argStack)
- {
- if (argInstr->m_opcode == Js::OpCode::StartCall)
- {
- startCall = argInstr;
- count++;
- if (count > 1)
- {
- return;
- }
- }
- } NEXT_SLIST_ENTRY;
- AnalysisAssert(startCall);
- if (startCall->m_prev->m_opcode != Js::OpCode::BailOnNoProfile)
- {
- InsertBailOnNoProfile(startCall);
- }
- }
- void IRBuilder::InsertBailOnNoProfile(IR::Instr *const insertBeforeInstr)
- {
- Assert(DoBailOnNoProfile());
- IR::Instr *const bailOnNoProfileInstr = IR::Instr::New(Js::OpCode::BailOnNoProfile, m_func);
- InsertInstr(bailOnNoProfileInstr, insertBeforeInstr);
- }
- #ifdef BAILOUT_INJECTION
- void
- IRBuilder::InjectBailOut(uint offset)
- {
- if(m_func->IsSimpleJit())
- {
- return; // bailout injection is only applicable to full JIT
- }
- IR::IntConstOpnd * opnd = IR::IntConstOpnd::New(0, TyInt32, m_func);
- uint bailOutOffset = offset;
- if (bailOutOffset == Js::Constants::NoByteCodeOffset)
- {
- bailOutOffset = m_lastInstr->GetByteCodeOffset();
- }
- BailOutInfo * bailOutInfo = JitAnew(m_func->m_alloc, BailOutInfo, bailOutOffset, m_func);
- IR::BailOutInstr * instr = IR::BailOutInstr::New(Js::OpCode::BailOnEqual, IR::BailOutInjected, bailOutInfo, bailOutInfo->bailOutFunc);
- instr->SetSrc1(opnd);
- instr->SetSrc2(opnd);
- this->AddInstr(instr, offset);
- }
- void
- IRBuilder::CheckBailOutInjection(Js::OpCode opcode)
- {
- // Detect these sequence and disable Bailout injection between them:
- // LdStackArgPtr
- // LdArgCnt
- // ApplyArgs
- // This assumes that LdStackArgPtr, LdArgCnt and ApplyArgs can
- // only be emitted in these sequence. This will need to be modified if it changes.
- //
- // Also insert a single bailout before the beginning of a switch case block for all the case labels.
- switch(opcode)
- {
- case Js::OpCode::LdStackArgPtr:
- Assert(!seenLdStackArgPtr);
- Assert(!expectApplyArg);
- seenLdStackArgPtr = true;
- break;
- case Js::OpCode::LdArgCnt:
- Assert(seenLdStackArgPtr);
- Assert(!expectApplyArg);
- expectApplyArg = true;
- break;
- case Js::OpCode::ApplyArgs:
- Assert(seenLdStackArgPtr);
- Assert(expectApplyArg);
- seenLdStackArgPtr = false;
- expectApplyArg = false;
- break;
- case Js::OpCode::BeginSwitch:
- case Js::OpCode::ProfiledBeginSwitch:
- Assert(!seenProfiledBeginSwitch);
- seenProfiledBeginSwitch = true;
- break;
- case Js::OpCode::EndSwitch:
- Assert(seenProfiledBeginSwitch);
- seenProfiledBeginSwitch = false;
- break;
- default:
- Assert(!seenLdStackArgPtr);
- Assert(!expectApplyArg);
- break;
- }
- }
- #endif
- bool
- IRBuilder::IsLoopBody() const
- {
- return m_func->IsLoopBody();
- }
- bool
- IRBuilder::IsLoopBodyInTry() const
- {
- return m_func->IsLoopBodyInTry();
- }
- bool
- IRBuilder::IsLoopBodyReturnIPInstr(IR::Instr * instr) const
- {
- IR::Opnd * dst = instr->GetDst();
- return (dst && dst->IsRegOpnd() && dst->AsRegOpnd()->m_sym == m_loopBodyRetIPSym);
- }
- bool
- IRBuilder::IsLoopBodyOuterOffset(uint offset) const
- {
- if (!IsLoopBody())
- {
- return false;
- }
- return (offset >= m_func->m_workItem->GetLoopHeader()->endOffset || offset < m_func->m_workItem->GetLoopHeader()->startOffset);
- }
- uint
- IRBuilder::GetLoopBodyExitInstrOffset() const
- {
- // End of loop body, start of StSlot and Ret instruction at endOffset + 1
- return m_func->m_workItem->GetLoopHeader()->endOffset + 1;
- }
- Js::RegSlot
- IRBuilder::GetEnvReg() const
- {
- return m_func->GetJITFunctionBody()->GetEnvReg();
- }
- Js::RegSlot
- IRBuilder::GetEnvRegForInnerFrameDisplay() const
- {
- Js::RegSlot envReg = m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg();
- if (envReg == Js::Constants::NoRegister)
- {
- envReg = this->GetEnvReg();
- }
- return envReg;
- }
- void
- IRBuilder::AddEnvOpndForInnerFrameDisplay(IR::Instr *instr, uint offset)
- {
- Js::RegSlot envReg = this->GetEnvRegForInnerFrameDisplay();
- if (envReg != Js::Constants::NoRegister)
- {
- IR::RegOpnd *src2Opnd;
- if (envReg == m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg() &&
- m_func->DoStackFrameDisplay() &&
- m_func->IsTopFunc())
- {
- src2Opnd = IR::RegOpnd::New(TyVar, m_func);
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::LdSlot, src2Opnd,
- this->BuildFieldOpnd(Js::OpCode::LdSlot, m_func->GetLocalFrameDisplaySym()->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlots),
- m_func),
- offset);
- }
- else
- {
- src2Opnd = this->BuildSrcOpnd(envReg);
- }
- instr->SetSrc2(src2Opnd);
- }
- }
- bool
- IRBuilder::DoSlotArrayCheck(IR::SymOpnd *fieldOpnd, bool doDynamicCheck)
- {
- if (PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
- {
- return true;
- }
- PropertySym *propertySym = fieldOpnd->m_sym->AsPropertySym();
- IR::Instr *instrDef = propertySym->m_stackSym->m_instrDef;
- IR::Opnd *allocOpnd = nullptr;
- if (instrDef == nullptr)
- {
- if (doDynamicCheck)
- {
- return false;
- }
- Js::Throw::FatalInternalError();
- }
- switch(instrDef->m_opcode)
- {
- case Js::OpCode::NewScopeSlots:
- case Js::OpCode::NewStackScopeSlots:
- case Js::OpCode::NewScopeSlotsWithoutPropIds:
- allocOpnd = instrDef->GetSrc1();
- break;
- case Js::OpCode::LdSlot:
- case Js::OpCode::LdSlotArr:
- if (doDynamicCheck)
- {
- return false;
- }
- // fall through
- default:
- Js::Throw::FatalInternalError();
- }
- uint32 allocCount = allocOpnd->AsIntConstOpnd()->AsUint32();
- uint32 slotId = (uint32)propertySym->m_propertyId;
- if (slotId >= allocCount)
- {
- Js::Throw::FatalInternalError();
- }
- return true;
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::Build
- ///
- /// IRBuilder main entry point. Read the bytecode for this function and
- /// generate IR.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::Build()
- {
- m_funcAlloc = m_func->m_alloc;
- NoRecoverMemoryJitArenaAllocator localAlloc(_u("BE-IRBuilder"), m_funcAlloc->GetPageAllocator(), Js::Throw::OutOfMemory);
- m_tempAlloc = &localAlloc;
- uint32 offset;
- uint32 statementIndex = m_statementReader.GetStatementIndex();
- m_argStack = JitAnew(m_tempAlloc, SList<IR::Instr *>, m_tempAlloc);
- this->branchRelocList = JitAnew(m_tempAlloc, SList<BranchReloc *>, m_tempAlloc);
- Func * topFunc = this->m_func->GetTopFunc();
- if (topFunc->HasTry() &&
- ((!topFunc->IsLoopBody() && !PHASE_OFF(Js::OptimizeTryCatchPhase, topFunc)) ||
- (topFunc->HasFinally() && !topFunc->IsLoopBody() && !PHASE_OFF(Js::OptimizeTryFinallyPhase, topFunc)) ||
- (topFunc->IsSimpleJit() && topFunc->GetJITFunctionBody()->DoJITLoopBody()) || // should be relaxed as more bailouts are added in Simple Jit
- topFunc->IsLoopBodyInTryFinally())) // We need accurate flow when we are full jitting loop bodies which have try finally
- {
- this->handlerOffsetStack = JitAnew(m_tempAlloc, SList<handlerStackElementType>, m_tempAlloc);
- }
- this->firstTemp = m_func->GetJITFunctionBody()->GetFirstTmpReg();
- Js::RegSlot tempCount = m_func->GetJITFunctionBody()->GetTempCount();
- if (tempCount > 0)
- {
- this->tempMap = AnewArrayZ(m_tempAlloc, SymID, tempCount);
- this->fbvTempUsed = BVFixed::New<JitArenaAllocator>(tempCount, m_tempAlloc);
- }
- else
- {
- this->tempMap = nullptr;
- this->fbvTempUsed = nullptr;
- }
- m_func->m_headInstr = IR::EntryInstr::New(Js::OpCode::FunctionEntry, m_func);
- m_func->m_exitInstr = IR::ExitInstr::New(Js::OpCode::FunctionExit, m_func);
- m_func->m_tailInstr = m_func->m_exitInstr;
- m_func->m_headInstr->InsertAfter(m_func->m_tailInstr);
- if (m_func->GetJITFunctionBody()->IsParamAndBodyScopeMerged() || this->IsLoopBody())
- {
- this->SetParamScopeDone();
- }
- if (m_func->GetJITFunctionBody()->GetLocalClosureReg() != Js::Constants::NoRegister)
- {
- m_func->InitLocalClosureSyms();
- }
- m_functionStartOffset = m_jnReader.GetCurrentOffset();
- m_lastInstr = m_func->m_headInstr;
- AssertMsg(sizeof(SymID) >= sizeof(Js::RegSlot), "sizeof(SymID) != sizeof(Js::RegSlot)!!");
- // Skip the last EndOfBlock opcode
- Assert(!OpCodeAttr::HasMultiSizeLayout(Js::OpCode::EndOfBlock));
- uint32 lastOffset = m_func->GetJITFunctionBody()->GetByteCodeLength() - Js::OpCodeUtil::EncodedSize(Js::OpCode::EndOfBlock, Js::SmallLayout);
- uint32 offsetToInstructionCount = lastOffset;
- if (this->IsLoopBody())
- {
- // LdSlot needs to cover all the register, including the temps, because we might treat
- // those as if they are local for the value of the with statement
- this->m_ldSlots = BVFixed::New<JitArenaAllocator>(m_func->GetJITFunctionBody()->GetLocalsCount(), m_tempAlloc);
- this->m_stSlots = BVFixed::New<JitArenaAllocator>(m_func->GetJITFunctionBody()->GetFirstTmpReg(), m_tempAlloc);
- this->m_loopBodyRetIPSym = StackSym::New(TyMachReg, this->m_func);
- #if DBG
- if (m_func->GetJITFunctionBody()->GetTempCount() != 0)
- {
- this->m_usedAsTemp = BVFixed::New<JitArenaAllocator>(m_func->GetJITFunctionBody()->GetTempCount(), m_tempAlloc);
- }
- #endif
- lastOffset = m_func->m_workItem->GetLoopHeader()->endOffset;
- AssertOrFailFast(lastOffset < m_func->GetJITFunctionBody()->GetByteCodeLength());
- // Ret is created at lastOffset + 1, so we need lastOffset + 2 entries
- offsetToInstructionCount = lastOffset + 2;
- // Compute the offset of the start of the locals array as a Var index.
- size_t localsOffset = Js::InterpreterStackFrame::GetOffsetOfLocals();
- Assert(localsOffset % sizeof(Js::Var) == 0);
- this->m_loopBodyLocalsStartSlot = (Js::PropertyId)(localsOffset / sizeof(Js::Var));
- }
- m_offsetToInstructionCount = offsetToInstructionCount;
- m_offsetToInstruction = JitAnewArrayZ(m_tempAlloc, IR::Instr *, offsetToInstructionCount);
- #ifdef BYTECODE_BRANCH_ISLAND
- longBranchMap = JitAnew(m_tempAlloc, LongBranchMap, m_tempAlloc);
- #endif
- m_switchBuilder.Init(m_func, m_tempAlloc, false);
- this->LoadNativeCodeData();
- this->BuildConstantLoads();
- this->BuildGeneratorPreamble();
- if (!this->IsLoopBody() && m_func->GetJITFunctionBody()->HasImplicitArgIns())
- {
- this->BuildImplicitArgIns();
- }
- if (!this->IsLoopBody() && m_func->GetJITFunctionBody()->HasRestParameter())
- {
- this->BuildArgInRest();
- }
- if (m_func->IsJitInDebugMode())
- {
- // This is first bailout in the function, the locals at stack have not initialized to undefined, so do not restore them.
- this->InsertBailOutForDebugger(m_functionStartOffset, IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction | IR::BailOutStep, nullptr);
- }
- #ifdef BAILOUT_INJECTION
- // Start bailout inject after the constant and arg load. We don't bailout before that
- IR::Instr * lastInstr = m_lastInstr;
- #endif
- offset = Js::Constants::NoByteCodeOffset;
- if (!this->IsLoopBody())
- {
- IR::Instr *instr;
- // Do the implicit operations LdEnv, NewScopeSlots, LdFrameDisplay, as indicated by function body attributes.
- Js::RegSlot envReg = m_func->GetJITFunctionBody()->GetEnvReg();
- if (envReg != Js::Constants::NoRegister && !this->RegIsConstant(envReg))
- {
- Js::OpCode newOpcode;
- Js::RegSlot thisReg = m_func->GetJITFunctionBody()->GetThisRegForEventHandler();
- IR::RegOpnd *srcOpnd = nullptr;
- IR::RegOpnd *dstOpnd = nullptr;
- if (thisReg != Js::Constants::NoRegister)
- {
- this->BuildArgIn0(offset, thisReg);
- srcOpnd = BuildSrcOpnd(thisReg);
- newOpcode = Js::OpCode::LdHandlerScope;
- }
- else
- {
- newOpcode = Js::OpCode::LdEnv;
- }
- dstOpnd = BuildDstOpnd(envReg);
- instr = IR::Instr::New(newOpcode, dstOpnd, m_func);
- if (srcOpnd)
- {
- instr->SetSrc1(srcOpnd);
- }
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- }
- Js::RegSlot funcExprScopeReg = m_func->GetJITFunctionBody()->GetFuncExprScopeReg();
- IR::RegOpnd *frameDisplayOpnd = nullptr;
- if (funcExprScopeReg != Js::Constants::NoRegister)
- {
- IR::RegOpnd *funcExprScopeOpnd = BuildDstOpnd(funcExprScopeReg);
- instr = IR::Instr::New(Js::OpCode::NewPseudoScope, funcExprScopeOpnd, m_func);
- this->AddInstr(instr, offset);
- }
- Js::RegSlot closureReg = m_func->GetJITFunctionBody()->GetLocalClosureReg();
- IR::RegOpnd *closureOpnd = nullptr;
- if (closureReg != Js::Constants::NoRegister)
- {
- Assert(!this->RegIsConstant(closureReg));
- if (m_func->DoStackScopeSlots())
- {
- closureOpnd = IR::RegOpnd::New(TyVar, m_func);
- }
- else
- {
- closureOpnd = this->BuildDstOpnd(closureReg);
- }
- if (m_func->GetJITFunctionBody()->HasScopeObject())
- {
- if (m_func->GetJITFunctionBody()->HasCachedScopePropIds())
- {
- this->BuildInitCachedScope(0, offset);
- }
- else
- {
- instr = IR::Instr::New(Js::OpCode::NewScopeObject, closureOpnd, m_func);
- this->AddInstr(instr, offset);
- }
- }
- else
- {
- Js::OpCode op =
- m_func->DoStackScopeSlots() ? Js::OpCode::NewStackScopeSlots : Js::OpCode::NewScopeSlots;
- uint size = m_func->GetJITFunctionBody()->IsParamAndBodyScopeMerged() ? m_func->GetJITFunctionBody()->GetScopeSlotArraySize() : m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
- IR::Opnd * srcOpnd = IR::IntConstOpnd::New(size + Js::ScopeSlots::FirstSlotIndex, TyUint32, m_func);
- instr = IR::Instr::New(op, closureOpnd, srcOpnd, m_func);
- this->AddInstr(instr, offset);
- }
- if (closureOpnd->m_sym->m_isSingleDef)
- {
- closureOpnd->m_sym->m_isNotNumber = true;
- }
- if (m_func->DoStackScopeSlots())
- {
- // Init the stack closure sym and use it to save the scope slot pointer.
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::InitLocalClosure, this->BuildDstOpnd(m_func->GetLocalClosureSym()->m_id), m_func),
- offset);
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::StSlot,
- this->BuildFieldOpnd(
- Js::OpCode::StSlot, m_func->GetLocalClosureSym()->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlots),
- closureOpnd, m_func),
- offset);
- }
- }
- Js::RegSlot frameDisplayReg = m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg();
- if (frameDisplayReg != Js::Constants::NoRegister)
- {
- Assert(!this->RegIsConstant(frameDisplayReg));
- Js::OpCode op = m_func->DoStackScopeSlots() ? Js::OpCode::NewStackFrameDisplay : Js::OpCode::LdFrameDisplay;
- if (funcExprScopeReg != Js::Constants::NoRegister)
- {
- // Insert the function expression scope ahead of any enclosing scopes.
- IR::RegOpnd * funcExprScopeOpnd = BuildSrcOpnd(funcExprScopeReg);
- frameDisplayOpnd = closureReg != Js::Constants::NoRegister ? IR::RegOpnd::New(TyVar, m_func) : BuildDstOpnd(frameDisplayReg);
- instr = IR::Instr::New(Js::OpCode::LdFrameDisplay, frameDisplayOpnd, funcExprScopeOpnd, m_func);
- if (envReg != Js::Constants::NoRegister)
- {
- instr->SetSrc2(this->BuildSrcOpnd(envReg));
- }
- this->AddInstr(instr, (uint)-1);
- }
- if (closureReg != Js::Constants::NoRegister)
- {
- IR::RegOpnd *dstOpnd;
- if (m_func->DoStackScopeSlots() && m_func->IsTopFunc())
- {
- dstOpnd = IR::RegOpnd::New(TyVar, m_func);
- }
- else
- {
- dstOpnd = this->BuildDstOpnd(frameDisplayReg);
- }
- instr = IR::Instr::New(op, dstOpnd, closureOpnd, m_func);
- if (frameDisplayOpnd != nullptr)
- {
- // We're building on an intermediate LdFrameDisplay result.
- instr->SetSrc2(frameDisplayOpnd);
- }
- else if (envReg != Js::Constants::NoRegister)
- {
- // We're building on the environment created by the enclosing function.
- instr->SetSrc2(this->BuildSrcOpnd(envReg));
- }
- this->AddInstr(instr, offset);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- if (m_func->DoStackFrameDisplay())
- {
- // Use the stack closure sym to save the frame display pointer.
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::InitLocalClosure, this->BuildDstOpnd(m_func->GetLocalFrameDisplaySym()->m_id), m_func),
- offset);
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::StSlot,
- this->BuildFieldOpnd(Js::OpCode::StSlot, m_func->GetLocalFrameDisplaySym()->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlots),
- dstOpnd, m_func),
- offset);
- }
- else if (m_func->GetTopFunc()->DoStackFrameDisplay())
- {
- Assert(m_func->GetLocalFrameDisplaySym() != nullptr);
- m_func->GetTopFunc()->AddInlineeFrameDisplaySym(m_func->GetLocalFrameDisplaySym());
- }
- }
- }
- }
- offset = m_functionStartOffset;
- if (m_statementReader.AtStatementBoundary(&m_jnReader))
- {
- statementIndex = this->AddStatementBoundary(statementIndex, offset);
- }
- // For label instr we can add bailout only after all labels were finalized. Put to list/add in the end.
- JsUtil::BaseDictionary<IR::Instr*, int, JitArenaAllocator> ignoreExBranchInstrToOffsetMap(m_tempAlloc);
- Js::LayoutSize layoutSize;
- IR::Instr* lastProcessedInstrForJITLoopBody = m_func->m_headInstr;
- for (Js::OpCode newOpcode = m_jnReader.ReadOp(layoutSize); (uint)m_jnReader.GetCurrentOffset() <= lastOffset; newOpcode = m_jnReader.ReadOp(layoutSize))
- {
- Assert(newOpcode != Js::OpCode::EndOfBlock);
- #ifdef BAILOUT_INJECTION
- if (!this->m_func->GetTopFunc()->HasTry()
- #ifdef BYTECODE_BRANCH_ISLAND
- && newOpcode != Js::OpCode::BrLong // Don't inject bailout on BrLong as they are just redirecting to a different offset anyways
- #endif
- )
- {
- if (!this->m_func->IsOOPJIT())
- {
- if (!seenLdStackArgPtr && !seenProfiledBeginSwitch)
- {
- if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutByteCodeFlag))
- {
- ThreadContext * threadContext = this->m_func->GetScriptContext()->GetThreadContext();
- if (Js::Configuration::Global.flags.BailOutByteCode.Contains(threadContext->bailOutByteCodeLocationCount))
- {
- this->InjectBailOut(offset);
- }
- }
- else if (Js::Configuration::Global.flags.IsEnabled(Js::BailOutAtEveryByteCodeFlag))
- {
- this->InjectBailOut(offset);
- }
- }
- CheckBailOutInjection(newOpcode);
- }
- }
- #endif
- AssertOrFailFastMsg(Js::OpCodeUtil::IsValidByteCodeOpcode(newOpcode), "Error getting opcode from m_jnReader.Op()");
- uint layoutAndSize = layoutSize * Js::OpLayoutType::Count + Js::OpCodeUtil::GetOpCodeLayout(newOpcode);
- switch(layoutAndSize)
- {
- #define LAYOUT_TYPE(layout) \
- case Js::OpLayoutType::layout: \
- Assert(layoutSize == Js::SmallLayout); \
- this->Build##layout(newOpcode, offset); \
- break;
- #define LAYOUT_TYPE_WMS(layout) \
- case Js::SmallLayout * Js::OpLayoutType::Count + Js::OpLayoutType::layout: \
- this->Build##layout<Js::SmallLayoutSizePolicy>(newOpcode, offset); \
- break; \
- case Js::MediumLayout * Js::OpLayoutType::Count + Js::OpLayoutType::layout: \
- this->Build##layout<Js::MediumLayoutSizePolicy>(newOpcode, offset); \
- break; \
- case Js::LargeLayout * Js::OpLayoutType::Count + Js::OpLayoutType::layout: \
- this->Build##layout<Js::LargeLayoutSizePolicy>(newOpcode, offset); \
- break;
- #include "ByteCode/LayoutTypes.h"
- default:
- AssertMsg(0, "Unimplemented layout");
- break;
- }
- #ifdef BAILOUT_INJECTION
- if (!this->m_func->IsOOPJIT())
- {
- if (!this->m_func->GetTopFunc()->HasTry() && Js::Configuration::Global.flags.IsEnabled(Js::BailOutByteCodeFlag))
- {
- ThreadContext * threadContext = this->m_func->GetScriptContext()->GetThreadContext();
- if (lastInstr != m_lastInstr)
- {
- lastInstr = lastInstr->GetNextRealInstr();
- if (lastInstr->HasBailOutInfo())
- {
- lastInstr = lastInstr->m_next;
- }
- lastInstr->bailOutByteCodeLocation = threadContext->bailOutByteCodeLocationCount;
- lastInstr = m_lastInstr;
- }
- threadContext->bailOutByteCodeLocationCount++;
- }
- }
- #endif
- if (IsLoopBodyInTry() && lastProcessedInstrForJITLoopBody != m_lastInstr)
- {
- // traverse in backward so we get new/later value of given symId for storing instead of the earlier/stale
- // symId value. m_stSlots is used to prevent multiple stores to the same symId.
- FOREACH_INSTR_BACKWARD_EDITING_IN_RANGE(
- instr,
- instrPrev,
- m_lastInstr,
- lastProcessedInstrForJITLoopBody->m_next)
- {
- if (instr->GetDst() && instr->GetDst()->IsRegOpnd() && instr->GetDst()->GetStackSym()->HasByteCodeRegSlot())
- {
- StackSym * dstSym = instr->GetDst()->GetStackSym();
- Js::RegSlot dstRegSlot = dstSym->GetByteCodeRegSlot();
- if (!this->RegIsTemp(dstRegSlot) && !this->RegIsConstant(dstRegSlot))
- {
- SymID symId = dstSym->m_id;
- AssertOrFailFast(symId < m_stSlots->Length());
- if (this->m_stSlots->Test(symId))
- {
- // For jitted loop bodies that are in a try block, we consider any symbol that has a
- // non-temp bytecode reg slot, to be write-through. Hence, generating StSlots at all
- // defs for such symbols
- IR::Instr * stSlot = this->GenerateLoopBodyStSlot(dstRegSlot);
- AddInstr(stSlot, Js::Constants::NoByteCodeOffset);
- this->m_stSlots->Clear(symId);
- }
- else
- {
- Assert(dstSym->m_isCatchObjectSym);
- }
- }
- }
- } NEXT_INSTR_BACKWARD_EDITING_IN_RANGE;
- lastProcessedInstrForJITLoopBody = m_lastInstr;
- }
- offset = m_jnReader.GetCurrentOffset();
- if (m_func->IsJitInDebugMode())
- {
- bool needBailoutForHelper = CONFIG_FLAG(EnableContinueAfterExceptionWrappersForHelpers) &&
- (OpCodeAttr::NeedsPostOpDbgBailOut(newOpcode) ||
- (m_lastInstr->m_opcode == Js::OpCode::CallHelper && m_lastInstr->GetSrc1() &&
- HelperMethodAttributes::CanThrow(m_lastInstr->GetSrc1()->AsHelperCallOpnd()->m_fnHelper)));
- if (needBailoutForHelper)
- {
- // Insert bailout after return from a helper call.
- // For now use offset of next instr, when we get & ignore exception, we replace this with next statement offset.
- if (m_lastInstr->IsBranchInstr())
- {
- // Debugger bailout on branches goes to different block which can become dead. Keep bailout with real instr.
- // Can't convert to bailout at this time, can do that only after branches are finalized, remember for later.
- ignoreExBranchInstrToOffsetMap.Add(m_lastInstr, offset);
- }
- else if (
- m_lastInstr->m_opcode == Js::OpCode::Throw ||
- m_lastInstr->m_opcode == Js::OpCode::RuntimeReferenceError ||
- m_lastInstr->m_opcode == Js::OpCode::RuntimeTypeError)
- {
- uint32 lastInstrOffset = m_lastInstr->GetByteCodeOffset();
- AssertOrFailFast(lastInstrOffset < m_offsetToInstructionCount);
- #if DBG
- __analysis_assume(lastInstrOffset < this->m_offsetToInstructionCount);
- #endif
- bool isLastInstrUpdateNeeded = m_offsetToInstruction[lastInstrOffset] == m_lastInstr;
- BailOutInfo * bailOutInfo = JitAnew(this->m_func->m_alloc, BailOutInfo, offset, this->m_func);
- m_lastInstr = m_lastInstr->ConvertToBailOutInstr(bailOutInfo, c_debuggerBaseBailOutKindForHelper, true);
- if (isLastInstrUpdateNeeded)
- {
- m_offsetToInstruction[lastInstrOffset] = m_lastInstr;
- }
- }
- else
- {
- IR::BailOutKind bailOutKind = c_debuggerBaseBailOutKindForHelper;
- if (OpCodeAttr::HasImplicitCall(newOpcode) || OpCodeAttr::OpndHasImplicitCall(newOpcode))
- {
- // When we get out of e.g. valueOf called by a helper (e.g. Add_A) during stepping,
- // we need to bail out to continue debugging calling function in interpreter,
- // essentially this is similar to bail out on return from a method.
- bailOutKind |= c_debuggerBailOutKindForCall;
- }
- this->InsertBailOutForDebugger(offset, bailOutKind);
- }
- }
- }
- while (m_statementReader.AtStatementBoundary(&m_jnReader))
- {
- statementIndex = this->AddStatementBoundary(statementIndex, offset);
- }
- }
- if (Js::Constants::NoStatementIndex != statementIndex)
- {
- // If we are inside a user statement then create a trailing line pragma instruction
- statementIndex = this->AddStatementBoundary(statementIndex, Js::Constants::NoByteCodeOffset);
- }
- if (IsLoopBody())
- {
- // Insert the LdSlot/StSlot and Ret
- IR::Opnd * retOpnd = this->InsertLoopBodyReturnIPInstr(offset, offset);
- // Restore and Ret are at the last offset + 1
- GenerateLoopBodySlotAccesses(lastOffset + 1);
- InsertDoneLoopBodyLoopCounter(lastOffset);
- IR::Instr * retInstr = IR::Instr::New(Js::OpCode::Ret, m_func);
- retInstr->SetSrc1(retOpnd);
- this->AddInstr(retInstr, lastOffset + 1);
- }
- // Now fix up the targets for all the branches we've introduced.
- InsertLabels();
- Assert(!this->handlerOffsetStack || this->handlerOffsetStack->Empty());
- // Insert bailout for ignore exception for labels, after all labels were finalized.
- ignoreExBranchInstrToOffsetMap.Map([this](IR::Instr* instr, int byteCodeOffset) {
- BailOutInfo * bailOutInfo = JitAnew(this->m_func->m_alloc, BailOutInfo, byteCodeOffset, this->m_func);
- instr->ConvertToBailOutInstr(bailOutInfo, c_debuggerBaseBailOutKindForHelper, true);
- });
- // Now that we know whether the func is a leaf or not, decide whether we'll emit fast paths.
- // Do this once and for all, per-func, since the source size on the ThreadContext will be
- // changing while we JIT.
- if (this->m_func->IsTopFunc())
- {
- this->m_func->SetDoFastPaths();
- this->EmitClosureRangeChecks();
- }
- }
- void
- IRBuilder::EmitClosureRangeChecks()
- {
- // Emit closure range checks
- if (m_func->slotArrayCheckTable)
- {
- // Local slot array checks, should only be necessary in jitted loop bodies.
- FOREACH_HASHTABLE_ENTRY(uint32, bucket, m_func->slotArrayCheckTable)
- {
- uint32 slotId = bucket.element;
- Assert(slotId != (uint32)-1 && slotId >= Js::ScopeSlots::FirstSlotIndex);
- if (slotId > Js::ScopeSlots::FirstSlotIndex)
- {
- // Emit a SlotArrayCheck instruction, chained to the instruction (LdSlot) that defines the pointer.
- StackSym *stackSym = m_func->m_symTable->FindStackSym(bucket.value);
- Assert(stackSym && stackSym->m_instrDef);
- IR::Instr *instrDef = stackSym->m_instrDef;
- IR::Instr *insertInstr = instrDef->m_next;
- IR::RegOpnd *dstOpnd = instrDef->UnlinkDst()->AsRegOpnd();
- IR::Instr *instr = IR::Instr::New(Js::OpCode::SlotArrayCheck, dstOpnd, m_func);
- dstOpnd = IR::RegOpnd::New(TyVar, m_func);
- instrDef->SetDst(dstOpnd);
- instr->SetSrc1(dstOpnd);
- // Attach the slot ID to the check instruction.
- IR::IntConstOpnd *slotIdOpnd = IR::IntConstOpnd::New(bucket.element, TyUint32, m_func);
- instr->SetSrc2(slotIdOpnd);
- insertInstr->InsertBefore(instr);
- }
- }
- NEXT_HASHTABLE_ENTRY;
- }
- if (m_func->frameDisplayCheckTable)
- {
- // Frame display checks. Again, chain to the instruction (LdEnv/LdSlot).
- FOREACH_HASHTABLE_ENTRY(FrameDisplayCheckRecord*, bucket, m_func->frameDisplayCheckTable)
- {
- StackSym *stackSym = m_func->m_symTable->FindStackSym(bucket.value);
- Assert(stackSym && stackSym->m_instrDef);
- IR::Instr *instrDef = stackSym->m_instrDef;
- IR::Instr *insertInstr = instrDef->m_next;
- IR::RegOpnd *dstOpnd = instrDef->UnlinkDst()->AsRegOpnd();
- IR::Instr *instr = IR::Instr::New(Js::OpCode::FrameDisplayCheck, dstOpnd, m_func);
- dstOpnd = IR::RegOpnd::New(TyVar, m_func);
- instrDef->SetDst(dstOpnd);
- instr->SetSrc1(dstOpnd);
- // Attach the two-dimensional check info.
- IR::AddrOpnd *recordOpnd = IR::AddrOpnd::New(bucket.element, IR::AddrOpndKindDynamicMisc, m_func, true);
- instr->SetSrc2(recordOpnd);
- insertInstr->InsertBefore(instr);
- }
- NEXT_HASHTABLE_ENTRY;
- }
- // If not a loop, but there are loops and trys, restore scope slot pointer and FD
- if (!m_func->IsLoopBody() && m_func->HasTry() && m_func->GetJITFunctionBody()->GetByteCodeInLoopCount() != 0)
- {
- BVSparse<JitArenaAllocator> * bv = nullptr;
- if (m_func->GetLocalClosureSym() && m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
- {
- bv = JitAnew(m_func->m_alloc, BVSparse<JitArenaAllocator>, m_func->m_alloc);
- bv->Set(m_func->GetLocalClosureSym()->m_id);
- }
- if (m_func->GetLocalFrameDisplaySym() && m_func->GetLocalFrameDisplaySym()->HasByteCodeRegSlot())
- {
- if (!bv)
- {
- bv = JitAnew(m_func->m_alloc, BVSparse<JitArenaAllocator>, m_func->m_alloc);
- }
- bv->Set(m_func->GetLocalFrameDisplaySym()->m_id);
- }
- if (bv)
- {
- FOREACH_INSTR_IN_FUNC_BACKWARD(instr, m_func)
- {
- if (instr->m_opcode == Js::OpCode::Ret)
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(instr);
- byteCodeUse->SetBV(bv);
- instr->InsertBefore(byteCodeUse);
- break;
- }
- }
- NEXT_INSTR_IN_FUNC_BACKWARD;
- }
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::InsertLabels
- ///
- /// Insert label instructions at the offsets recorded in the branch reloc list.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::InsertLabels()
- {
- AssertMsg(this->branchRelocList, "Malformed branch reloc list");
- SList<BranchReloc *>::Iterator iter(this->branchRelocList);
- while (iter.Next())
- {
- IR::LabelInstr * labelInstr = nullptr;
- BranchReloc * reloc = iter.Data();
- IR::BranchInstr * branchInstr = reloc->GetBranchInstr();
- uint offset = reloc->GetOffset();
- uint const branchOffset = reloc->GetBranchOffset();
- Assert(!IsLoopBody() || offset <= GetLoopBodyExitInstrOffset());
- if(branchInstr->m_opcode == Js::OpCode::MultiBr)
- {
- IR::MultiBranchInstr * multiBranchInstr = branchInstr->AsBranchInstr()->AsMultiBrInstr();
- multiBranchInstr->UpdateMultiBrTargetOffsets([&](uint32 offset) -> IR::LabelInstr *
- {
- labelInstr = this->CreateLabel(branchInstr, offset);
- multiBranchInstr->ChangeLabelRef(nullptr, labelInstr);
- return labelInstr;
- });
- }
- else
- {
- labelInstr = this->CreateLabel(branchInstr, offset);
- branchInstr->SetTarget(labelInstr);
- }
- if (!reloc->IsNotBackEdge() && branchOffset >= offset)
- {
- bool wasLoopTop = labelInstr->m_isLoopTop;
- labelInstr->m_isLoopTop = true;
- if (m_func->IsJitInDebugMode())
- {
- // Add bailout for Async Break.
- IR::BranchInstr* backEdgeBranchInstr = reloc->GetBranchInstr();
- this->InsertBailOutForDebugger(backEdgeBranchInstr->GetByteCodeOffset(), IR::BailOutForceByFlag | IR::BailOutBreakPointInFunction, backEdgeBranchInstr);
- }
- if (!wasLoopTop && m_loopCounterSym)
- {
- this->InsertIncrLoopBodyLoopCounter(labelInstr);
- }
- }
- }
- }
- IR::LabelInstr *
- IRBuilder::CreateLabel(IR::BranchInstr * branchInstr, uint& offset)
- {
- IR::LabelInstr * labelInstr;
- IR::Instr * targetInstr;
- for (;;)
- {
- AssertOrFailFast(offset < m_offsetToInstructionCount);
- targetInstr = this->m_offsetToInstruction[offset];
- if (targetInstr != nullptr)
- {
- #ifdef BYTECODE_BRANCH_ISLAND
- // If we have a long branch, remap it to the target offset
- if (targetInstr == VirtualLongBranchInstr)
- {
- offset = ResolveVirtualLongBranch(branchInstr, offset);
- continue;
- }
- #endif
- break;
- }
- offset++;
- }
- IR::Instr *instrPrev = targetInstr->m_prev;
- if (instrPrev)
- {
- instrPrev = targetInstr->GetPrevRealInstrOrLabel();
- }
- if (instrPrev && instrPrev->IsLabelInstr() && instrPrev->GetByteCodeOffset() == offset)
- {
- // Found an existing label at the right offset. Just reuse it.
- labelInstr = instrPrev->AsLabelInstr();
- }
- else
- {
- // No label at the desired offset. Create one.
- labelInstr = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
- labelInstr->SetByteCodeOffset(offset);
- if (instrPrev)
- {
- instrPrev->InsertAfter(labelInstr);
- }
- else
- {
- targetInstr->InsertBefore(labelInstr);
- }
- }
- return labelInstr;
- }
- void IRBuilder::InsertInstr(IR::Instr *instr, IR::Instr* insertBeforeInstr)
- {
- AssertOrFailFast(insertBeforeInstr->GetByteCodeOffset() < m_offsetToInstructionCount);
- instr->SetByteCodeOffset(insertBeforeInstr);
- uint32 offset = insertBeforeInstr->GetByteCodeOffset();
- if (m_offsetToInstruction[offset] == insertBeforeInstr)
- {
- m_offsetToInstruction[offset] = instr;
- }
- insertBeforeInstr->InsertBefore(instr);
- #if DBG_DUMP
- if (PHASE_TRACE(Js::IRBuilderPhase, m_func->GetTopFunc()))
- {
- instr->Dump();
- }
- #endif
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::AddInstr
- ///
- /// Add an instruction to the current instr list. Also add this instr to
- /// offsetToinstruction table to patch branches/labels afterwards.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::AddInstr(IR::Instr *instr, uint32 offset)
- {
- m_lastInstr->InsertAfter(instr);
- if (offset != Js::Constants::NoByteCodeOffset)
- {
- AssertOrFailFast(offset < m_offsetToInstructionCount);
- if (m_offsetToInstruction[offset] == nullptr)
- {
- m_offsetToInstruction[offset] = instr;
- }
- else
- {
- Assert(m_lastInstr->GetByteCodeOffset() == offset);
- }
- if (instr->GetByteCodeOffset() == Js::Constants::NoByteCodeOffset)
- {
- instr->SetByteCodeOffset(offset);
- }
- }
- else
- {
- instr->SetByteCodeOffset(m_lastInstr->GetByteCodeOffset());
- }
- m_lastInstr = instr;
- Func *topFunc = this->m_func->GetTopFunc();
- if (!topFunc->GetHasTempObjectProducingInstr())
- {
- if (OpCodeAttr::TempObjectProducing(instr->m_opcode))
- {
- topFunc->SetHasTempObjectProducingInstr(true);
- }
- }
- #if DBG_DUMP
- if (Js::Configuration::Global.flags.Trace.IsEnabled(Js::IRBuilderPhase, this->m_func->GetTopFunc()->GetSourceContextId(), this->m_func->GetTopFunc()->GetLocalFunctionId()))
- {
- instr->Dump();
- }
- #endif
- }
- IR::IndirOpnd *
- IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, IR::RegOpnd *indexReg)
- {
- IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseReg, indexReg, TyVar, m_func);
- return indirOpnd;
- }
- IR::IndirOpnd *
- IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset)
- {
- IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseReg, offset, TyVar, m_func);
- return indirOpnd;
- }
- #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
- IR::IndirOpnd *
- IRBuilder::BuildIndirOpnd(IR::RegOpnd *baseReg, uint32 offset, const char16 *desc)
- {
- IR::IndirOpnd *indirOpnd = IR::IndirOpnd::New(baseReg, offset, TyVar, desc, m_func);
- return indirOpnd;
- }
- #endif
- IR::SymOpnd *
- IRBuilder::BuildFieldOpnd(Js::OpCode newOpcode, Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, PropertyKind propertyKind, uint inlineCacheIndex)
- {
- AssertOrFailFast(inlineCacheIndex < m_func->GetJITFunctionBody()->GetInlineCacheCount() || inlineCacheIndex == Js::Constants::NoInlineCacheIndex);
- PropertySym * propertySym = BuildFieldSym(reg, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind);
- IR::SymOpnd * symOpnd;
- // If we plan to apply object type optimization to this instruction or if we intend to emit a fast path using an inline
- // cache, we will need a property sym operand.
- if (OpCodeAttr::FastFldInstr(newOpcode) || inlineCacheIndex != (uint)-1)
- {
- Assert(propertyKind == PropertyKindData);
- symOpnd = IR::PropertySymOpnd::New(propertySym, inlineCacheIndex, TyVar, this->m_func);
- if (inlineCacheIndex != (uint)-1 && propertySym->m_loadInlineCacheIndex == (uint)-1)
- {
- if (GlobOpt::IsPREInstrCandidateLoad(newOpcode))
- {
- propertySym->m_loadInlineCacheIndex = inlineCacheIndex;
- propertySym->m_loadInlineCacheFunc = this->m_func;
- }
- }
- }
- else
- {
- symOpnd = IR::SymOpnd::New(propertySym, TyVar, this->m_func);
- }
- return symOpnd;
- }
- PropertySym *
- IRBuilder::BuildFieldSym(Js::RegSlot reg, Js::PropertyId propertyId, Js::PropertyIdIndexType propertyIdIndex, uint inlineCacheIndex, PropertyKind propertyKind)
- {
- PropertySym * propertySym;
- SymID symId = this->BuildSrcStackSymID(reg);
- AssertMsg(m_func->m_symTable->FindStackSym(symId), "Tried to use an undefined stacksym?");
- propertySym = PropertySym::FindOrCreate(symId, propertyId, propertyIdIndex, inlineCacheIndex, propertyKind, m_func);
- return propertySym;
- }
- SymID
- IRBuilder::BuildSrcStackSymID(Js::RegSlot regSlot)
- {
- SymID symID;
- if (this->RegIsTemp(regSlot))
- {
- // This is a use of a temp. Map the reg slot to its sym ID.
- // !!!NOTE: always process an instruction's temp uses before its temp defs!!!
- symID = this->GetMappedTemp(regSlot);
- if (symID == 0)
- {
- // We might have temps that are live through the loop body via "with" statement
- // We need to treat those as if they are locals and don't remap them
- Assert(this->IsLoopBody());
- Assert(!this->m_usedAsTemp->Test(regSlot - m_func->GetJITFunctionBody()->GetFirstTmpReg()));
- symID = static_cast<SymID>(regSlot);
- this->SetMappedTemp(regSlot, symID);
- this->EnsureLoopBodyLoadSlot(symID);
- }
- this->SetTempUsed(regSlot, TRUE);
- }
- else
- {
- symID = static_cast<SymID>(regSlot);
- if (IsLoopBody() && !this->RegIsConstant(regSlot))
- {
- this->EnsureLoopBodyLoadSlot(symID);
- }
- }
- return symID;
- }
- IR::RegOpnd *
- IRBuilder::EnsureLoopBodyForInEnumeratorArrayOpnd()
- {
- Assert(this->IsLoopBody());
- IR::RegOpnd * loopBodyForInEnumeratorArrayOpnd = this->m_loopBodyForInEnumeratorArrayOpnd;
- if (loopBodyForInEnumeratorArrayOpnd == nullptr)
- {
- loopBodyForInEnumeratorArrayOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
- this->m_loopBodyForInEnumeratorArrayOpnd = loopBodyForInEnumeratorArrayOpnd;
- StackSym *loopParamSym = m_func->EnsureLoopParamSym();
- IR::RegOpnd *loopParamOpnd = IR::RegOpnd::New(loopParamSym, TyMachPtr, m_func);
- IR::Instr * ldInstr = IR::Instr::New(Js::OpCode::Ld_A, loopBodyForInEnumeratorArrayOpnd,
- IR::IndirOpnd::New(loopParamOpnd, Js::InterpreterStackFrame::GetOffsetOfForInEnumerators(), TyMachPtr, this->m_func),
- this->m_func);
- m_func->m_headInstr->InsertAfter(ldInstr);
- }
- return loopBodyForInEnumeratorArrayOpnd;
- }
- IR::Opnd *
- IRBuilder::BuildForInEnumeratorOpnd(uint forInLoopLevel)
- {
- Assert(forInLoopLevel < this->m_func->GetJITFunctionBody()->GetForInLoopDepth());
- if (!this->IsLoopBody())
- {
- StackSym *stackSym = StackSym::New(TyMisc, this->m_func);
- stackSym->m_offset = forInLoopLevel;
- return IR::SymOpnd::New(stackSym, TyMachPtr, this->m_func);
- }
- return IR::IndirOpnd::New(
- EnsureLoopBodyForInEnumeratorArrayOpnd(), forInLoopLevel * sizeof(Js::ForInObjectEnumerator), TyMachPtr, this->m_func);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildSrcOpnd
- ///
- /// Create a StackSym and return a RegOpnd for this RegSlot.
- ///
- ///----------------------------------------------------------------------------
- IR::RegOpnd *
- IRBuilder::BuildSrcOpnd(Js::RegSlot srcRegSlot, IRType type)
- {
- StackSym * symSrc = m_func->m_symTable->FindStackSym(BuildSrcStackSymID(srcRegSlot));
- AssertMsg(symSrc, "Tried to use an undefined stack slot?");
- IR::RegOpnd *regOpnd = IR::RegOpnd::New(symSrc, type, m_func);
- return regOpnd;
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildDstOpnd
- ///
- /// Create a StackSym and return a RegOpnd for this RegSlot.
- /// If the RegSlot is '0', it may have multiple defs, so use FindOrCreate.
- ///
- ///----------------------------------------------------------------------------
- IR::RegOpnd *
- IRBuilder::BuildDstOpnd(Js::RegSlot dstRegSlot, IRType type, bool isCatchObjectSym)
- {
- StackSym * symDst;
- SymID symID;
- if (this->RegIsTemp(dstRegSlot))
- {
- #if DBG
- if (this->IsLoopBody())
- {
- // If we are doing loop body, and a temp reg slot is loaded via LdSlot
- // That means that we have detected that the slot is live coming in to the loop.
- // This would only happen for the value of a "with" statement, so there shouldn't
- // be any def for those
- Assert(!this->m_ldSlots->Test(dstRegSlot));
- this->m_usedAsTemp->Set(dstRegSlot - m_func->GetJITFunctionBody()->GetFirstTmpReg());
- }
- #endif
- // This is a def of a temp. Create a new sym ID for it if it's been used since its last def.
- // !!!NOTE: always process an instruction's temp uses before its temp defs!!!
- if (this->GetTempUsed(dstRegSlot))
- {
- symID = m_func->m_symTable->NewID();
- this->SetTempUsed(dstRegSlot, FALSE);
- this->SetMappedTemp(dstRegSlot, symID);
- }
- else
- {
- symID = this->GetMappedTemp(dstRegSlot);
- // The temp hasn't been used since its last def. There are 2 possibilities:
- if (symID == 0)
- {
- // First time we've seen the temp. Just use the number that the front end gave it.
- symID = static_cast<SymID>(dstRegSlot);
- this->SetMappedTemp(dstRegSlot, symID);
- }
- }
- }
- else
- {
- symID = static_cast<SymID>(dstRegSlot);
- if (this->RegIsConstant(dstRegSlot))
- {
- // Don't need to track constant registers for bailout. Don't set the byte code register for constant.
- dstRegSlot = Js::Constants::NoRegister;
- }
- else if (IsLoopBody())
- {
- // Loop body and not constants
- this->SetLoopBodyStSlot(symID, isCatchObjectSym);
- // We need to make sure that the symbols is loaded as well
- // so that the sym will be defined on all path.
- this->EnsureLoopBodyLoadSlot(symID, isCatchObjectSym);
- }
- }
- symDst = StackSym::FindOrCreate(symID, dstRegSlot, m_func);
- // Always reset isSafeThis to false. We'll set it to true for singleDef cases,
- // but want to reset it to false if it is multi-def.
- // NOTE: We could handle the multiDef if they are all safe, but it probably isn't very common.
- symDst->m_isSafeThis = false;
- IR::RegOpnd *regOpnd = IR::RegOpnd::New(symDst, type, m_func);
- return regOpnd;
- }
- void
- IRBuilder::BuildImplicitArgIns()
- {
- Js::RegSlot startReg = m_func->GetJITFunctionBody()->GetConstCount() - 1;
- for (Js::ArgSlot i = 1; i < m_func->GetJITFunctionBody()->GetInParamsCount(); i++)
- {
- this->BuildArgIn((uint32)-1, startReg + i, i);
- }
- }
- #if DBG_DUMP || defined(ENABLE_IR_VIEWER)
- #define POINTER_OFFSET(opnd, c, field) \
- BuildIndirOpnd((opnd), c::Get##field##Offset(), _u(#c) _u(".") _u(#field))
- #else
- #define POINTER_OFFSET(opnd, c, field) \
- BuildIndirOpnd((opnd), c::Get##field##Offset())
- #endif
- void
- IRBuilder::BuildGeneratorPreamble()
- {
- if (!this->m_func->GetJITFunctionBody()->IsCoroutine())
- {
- return;
- }
- // Build code to check if the generator already has state and if it does then jump to the corresponding resume point.
- // Otherwise jump to the start of the function. The generator object is the first argument by convention established
- // in JavascriptGenerator::EntryNext/EntryReturn/EntryThrow.
- //
- // s1 = Ld_A prm1
- // s2 = Ld_A s1[offset of JavascriptGenerator::frame]
- // BrAddr_A s2 nullptr $startOfFunc
- // s3 = Ld_A s2[offset of InterpreterStackFrame::m_reader.m_currentLocation]
- // s4 = Ld_A s2[offset of InterpreterStackFrame::m_reader.m_startLocation]
- // s5 = Sub_I4 s3 s4
- // GeneratorResumeJumpTable s5
- // $startOfFunc:
- //
- StackSym *genParamSym = StackSym::NewParamSlotSym(1, this->m_func);
- this->m_func->SetArgOffset(genParamSym, LowererMD::GetFormalParamOffset() * MachPtr);
- IR::SymOpnd *genParamOpnd = IR::SymOpnd::New(genParamSym, TyMachPtr, this->m_func);
- IR::RegOpnd *genRegOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
- IR::Instr *instr = IR::Instr::New(Js::OpCode::Ld_A, genRegOpnd, genParamOpnd, this->m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::RegOpnd *genFrameOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
- instr = IR::Instr::New(Js::OpCode::Ld_A, genFrameOpnd, POINTER_OFFSET(genRegOpnd, Js::JavascriptGenerator, Frame), this->m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::LabelInstr *labelInstr = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
- IR::BranchInstr *branchInstr = IR::BranchInstr::New(Js::OpCode::BrAddr_A, labelInstr, genFrameOpnd, IR::AddrOpnd::NewNull(this->m_func), this->m_func);
- this->AddInstr(branchInstr, Js::Constants::NoByteCodeOffset);
- IR::RegOpnd *curLocOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
- instr = IR::Instr::New(Js::OpCode::Ld_A, curLocOpnd, POINTER_OFFSET(genFrameOpnd, Js::InterpreterStackFrame, CurrentLocation), this->m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::RegOpnd *startLocOpnd = IR::RegOpnd::New(TyMachPtr, this->m_func);
- instr = IR::Instr::New(Js::OpCode::Ld_A, startLocOpnd, POINTER_OFFSET(genFrameOpnd, Js::InterpreterStackFrame, StartLocation), this->m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::RegOpnd *curOffsetOpnd = IR::RegOpnd::New(TyUint32, this->m_func);
- instr = IR::Instr::New(Js::OpCode::Sub_I4, curOffsetOpnd, curLocOpnd, startLocOpnd, this->m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::GeneratorResumeJumpTable, this->m_func);
- instr->SetSrc1(curOffsetOpnd);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- this->AddInstr(labelInstr, Js::Constants::NoByteCodeOffset);
- }
- void
- IRBuilder::LoadNativeCodeData()
- {
- if (m_func->IsOOPJIT() && m_func->IsTopFunc())
- {
- IR::RegOpnd * nativeDataOpnd = IR::RegOpnd::New(TyVar, m_func);
- IR::Instr * instr = IR::Instr::New(Js::OpCode::LdNativeCodeData, nativeDataOpnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- m_func->SetNativeCodeDataSym(nativeDataOpnd->GetStackSym());
- }
- }
- void
- IRBuilder::BuildConstantLoads()
- {
- Js::RegSlot count = m_func->GetJITFunctionBody()->GetConstCount();
- for (Js::RegSlot reg = Js::FunctionBody::FirstRegSlot; reg < count; reg++)
- {
- intptr_t varConst = m_func->GetJITFunctionBody()->GetConstantVar(reg);
- Assert(varConst != 0);
- Js::TypeId type = m_func->GetJITFunctionBody()->GetConstantType(reg);
- IR::RegOpnd *dstOpnd = this->BuildDstOpnd(reg);
- Assert(this->RegIsConstant(reg));
- dstOpnd->m_sym->SetIsFromByteCodeConstantTable();
- // TODO: be more precise about this
- ValueType valueType;
- IR::Instr *instr = nullptr;
- switch (type)
- {
- case Js::TypeIds_Number:
- valueType = ValueType::Number;
- instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func
- #if !FLOATVAR
- , m_func->IsOOPJIT() ? m_func->GetJITFunctionBody()->GetConstAsT<Js::JavascriptNumber>(reg) : nullptr
- #endif
- );
- break;
- case Js::TypeIds_String:
- {
- valueType = ValueType::String;
- if (m_func->IsOOPJIT())
- {
- // must be either PropertyString or LiteralString
- JITRecyclableObject * jitObj = m_func->GetJITFunctionBody()->GetConstantContent(reg);
- JITJavascriptString * constStr = JITJavascriptString::FromVar(jitObj);
- instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func, constStr);
- }
- else
- {
- instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func);
- }
- break;
- }
- case Js::TypeIds_Limit:
- valueType = ValueType::FromTypeId(type, false);
- instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func);
- break;
- default:
- valueType = ValueType::FromTypeId(type, false);
- instr = IR::Instr::NewConstantLoad(dstOpnd, varConst, valueType, m_func,
- m_func->IsOOPJIT() ? m_func->GetJITFunctionBody()->GetConstAsT<Js::RecyclableObject>(reg) : nullptr);
- break;
- }
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg1
- ///
- /// Build IR instr for a Reg1 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- }
- BuildReg1(newOpcode, offset, layout->R0);
- }
- void
- IRBuilder::BuildReg1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0)
- {
- if (newOpcode == Js::OpCode::ArgIn0)
- {
- this->BuildArgIn0(offset, R0);
- return;
- }
- IR::Instr * instr;
- Js::RegSlot srcRegOpnd, dstRegSlot;
- srcRegOpnd = dstRegSlot = R0;
- IR::Opnd * srcOpnd = nullptr;
- bool isNotInt = false;
- bool dstIsCatchObject = false;
- ValueType dstValueType;
- switch (newOpcode)
- {
- case Js::OpCode::LdLetHeapArguments:
- {
- this->m_func->SetHasNonSimpleParams();
- //FallThrough to next case block!
- }
- case Js::OpCode::LdHeapArguments:
- {
- if (this->m_func->GetJITFunctionBody()->NeedScopeObjectForArguments(m_func->GetHasNonSimpleParams()))
- {
- Js::RegSlot regFrameObj = m_func->GetJITFunctionBody()->GetLocalClosureReg();
- Assert(regFrameObj != Js::Constants::NoRegister);
- srcOpnd = BuildSrcOpnd(regFrameObj);
- if (m_func->GetJITFunctionBody()->GetInParamsCount() > 1)
- {
- m_func->SetScopeObjSym(srcOpnd->GetStackSym());
- }
- }
- else
- {
- srcOpnd = IR::AddrOpnd::New(
- m_func->GetScriptContextInfo()->GetNullAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- }
- IR::RegOpnd * dstOpnd = BuildDstOpnd(R0);
- instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- this->AddInstr(instr, offset);
- StackSym * dstSym = dstOpnd->m_sym;
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isSafeThis = true;
- dstSym->m_isNotNumber = true;
- }
- return;
- }
- case Js::OpCode::LdLetHeapArgsCached:
- {
- this->m_func->SetHasNonSimpleParams();
- //Fallthrough to next case block!
- }
- case Js::OpCode::LdHeapArgsCached:
- if (!m_func->GetJITFunctionBody()->HasScopeObject())
- {
- Js::Throw::FatalInternalError();
- }
- srcOpnd = BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
- if (m_func->GetJITFunctionBody()->GetInParamsCount() > 1)
- {
- m_func->SetScopeObjSym(srcOpnd->GetStackSym());
- }
- isNotInt = true;
- break;
- case Js::OpCode::LdLocalObj:
- if (!m_func->GetJITFunctionBody()->HasScopeObject())
- {
- Js::Throw::FatalInternalError();
- }
- srcOpnd = BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
- isNotInt = true;
- newOpcode = Js::OpCode::Ld_A;
- break;
- case Js::OpCode::LdParamObj:
- if (!m_func->GetJITFunctionBody()->HasScopeObject())
- {
- Js::Throw::FatalInternalError();
- }
- srcOpnd = BuildSrcOpnd(m_func->GetJITFunctionBody()->GetParamClosureReg());
- isNotInt = true;
- newOpcode = Js::OpCode::Ld_A;
- break;
- case Js::OpCode::Throw:
- {
- srcOpnd = this->BuildSrcOpnd(srcRegOpnd);
- if ((this->handlerOffsetStack && !this->handlerOffsetStack->Empty()) ||
- finallyBlockLevel > 0)
- {
- newOpcode = Js::OpCode::EHThrow;
- }
- instr = IR::Instr::New(newOpcode, m_func);
- instr->SetSrc1(srcOpnd);
- this->AddInstr(instr, offset);
- if(DoBailOnNoProfile())
- {
- //So optimistically assume it doesn't throw and introduce bailonnoprofile here.
- //If there are continuous bailout bailonnoprofile will be disabled.
- InsertBailOnNoProfile(instr);
- }
- return;
- }
- case Js::OpCode::LdC_A_Null:
- {
- const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetNullAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- addrOpnd->SetValueType(ValueType::Null);
- srcOpnd = addrOpnd;
- newOpcode = Js::OpCode::Ld_A;
- break;
- }
- case Js::OpCode::LdUndef:
- {
- const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndefinedAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- addrOpnd->SetValueType(ValueType::Undefined);
- srcOpnd = addrOpnd;
- newOpcode = Js::OpCode::Ld_A;
- break;
- }
- case Js::OpCode::LdInfinity:
- {
- const auto floatConstOpnd = IR::FloatConstOpnd::New(Js::JavascriptNumber::POSITIVE_INFINITY, TyFloat64, m_func);
- srcOpnd = floatConstOpnd;
- newOpcode = Js::OpCode::LdC_A_R8;
- break;
- }
- case Js::OpCode::LdNaN:
- {
- const auto floatConstOpnd = IR::FloatConstOpnd::New(Js::JavascriptNumber::NaN, TyFloat64, m_func);
- srcOpnd = floatConstOpnd;
- newOpcode = Js::OpCode::LdC_A_R8;
- break;
- }
- case Js::OpCode::LdFalse:
- {
- const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetFalseAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- addrOpnd->SetValueType(ValueType::Boolean);
- srcOpnd = addrOpnd;
- newOpcode = Js::OpCode::Ld_A;
- break;
- }
- case Js::OpCode::LdTrue:
- {
- const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetTrueAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- addrOpnd->SetValueType(ValueType::Boolean);
- srcOpnd = addrOpnd;
- newOpcode = Js::OpCode::Ld_A;
- break;
- }
- case Js::OpCode::NewScObjectSimple:
- dstValueType = ValueType::GetObject(ObjectType::UninitializedObject);
- // fall-through
- case Js::OpCode::LdFuncExpr:
- m_func->DisableCanDoInlineArgOpt();
- break;
- case Js::OpCode::LdEnv:
- case Js::OpCode::LdHomeObj:
- case Js::OpCode::LdFuncObj:
- isNotInt = TRUE;
- break;
- case Js::OpCode::Unused:
- // Don't generate anything. Just indicate that the temp reg is used.
- Assert(this->RegIsTemp(dstRegSlot));
- this->SetTempUsed(dstRegSlot, TRUE);
- return;
- case Js::OpCode::InitUndecl:
- srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
- newOpcode = Js::OpCode::Ld_A;
- break;
- case Js::OpCode::ChkUndecl:
- srcOpnd = BuildSrcOpnd(srcRegOpnd);
- instr = IR::Instr::New(Js::OpCode::ChkUndecl, m_func);
- instr->SetSrc1(srcOpnd);
- this->AddInstr(instr, offset);
- return;
- case Js::OpCode::Catch:
- if (this->handlerOffsetStack)
- {
- AssertOrFailFast(!this->handlerOffsetStack->Empty());
- AssertOrFailFast(this->handlerOffsetStack->Top().Second() == true);
- this->handlerOffsetStack->Pop();
- }
- dstIsCatchObject = true;
- break;
- case Js::OpCode::LdChakraLib:
- {
- const auto addrOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetChakraLibAddr(), IR::AddrOpndKindDynamicVar, m_func, true);
- addrOpnd->SetValueType(ValueType::PrimitiveOrObject);
- srcOpnd = addrOpnd;
- newOpcode = Js::OpCode::Ld_A;
- break;
- }
- }
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot, TyVar, dstIsCatchObject);
- dstOpnd->SetValueType(dstValueType);
- StackSym * dstSym = dstOpnd->m_sym;
- dstSym->m_isCatchObjectSym = dstIsCatchObject;
- instr = IR::Instr::New(newOpcode, dstOpnd, m_func);
- if (srcOpnd)
- {
- instr->SetSrc1(srcOpnd);
- if (dstSym->m_isSingleDef)
- {
- if (srcOpnd->IsHelperCallOpnd())
- {
- // Don't do anything
- }
- else if (srcOpnd->IsIntConstOpnd())
- {
- dstSym->SetIsIntConst(srcOpnd->AsIntConstOpnd()->GetValue());
- }
- else if (srcOpnd->IsFloatConstOpnd())
- {
- dstSym->SetIsFloatConst();
- }
- else if (srcOpnd->IsAddrOpnd())
- {
- dstSym->m_isConst = true;
- dstSym->m_isNotNumber = true;
- }
- }
- }
- if (isNotInt && dstSym->m_isSingleDef)
- {
- dstSym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg2
- ///
- /// Build IR instr for a Reg2 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode) || newOpcode == Js::OpCode::ProfiledStrictLdThis);
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- }
- BuildReg2(newOpcode, offset, layout->R0, layout->R1, m_jnReader.GetCurrentOffset());
- }
- void
- IRBuilder::BuildReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, Js::RegSlot R1, uint32 nextOffset)
- {
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(R1);
- StackSym * symSrc1 = src1Opnd->m_sym;
- switch (newOpcode)
- {
- case Js::OpCode::SetComputedNameVar:
- {
- IR::Instr *instr = IR::Instr::New(Js::OpCode::SetComputedNameVar, m_func);
- instr->SetSrc1(this->BuildSrcOpnd(R0));
- instr->SetSrc2(src1Opnd);
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::LdFuncExprFrameDisplay:
- {
- IR::RegOpnd *dstOpnd = IR::RegOpnd::New(TyVar, m_func);
- IR::Instr *instr = IR::Instr::New(Js::OpCode::LdFrameDisplay, dstOpnd, src1Opnd, m_func);
- Js::RegSlot envReg = this->GetEnvReg();
- if (envReg != Js::Constants::NoRegister)
- {
- instr->SetSrc2(BuildSrcOpnd(envReg));
- }
- this->AddInstr(instr, offset);
- IR::RegOpnd *src2Opnd = dstOpnd;
- src1Opnd = BuildSrcOpnd(R0);
- dstOpnd = BuildDstOpnd(m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg());
- instr = IR::Instr::New(Js::OpCode::LdFrameDisplay, dstOpnd, src1Opnd, src2Opnd, m_func);
- dstOpnd->m_sym->m_isNotNumber = true;
- this->AddInstr(instr, offset);
- return;
- }
- }
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(R0);
- StackSym * dstSym = dstOpnd->m_sym;
- IR::Instr * instr = nullptr;
- switch (newOpcode)
- {
- case Js::OpCode::Ld_A:
- if (symSrc1->m_builtInIndex != Js::BuiltinFunction::None)
- {
- // Note: don't set dstSym->m_builtInIndex to None here (see Win8 399972)
- dstSym->m_builtInIndex = symSrc1->m_builtInIndex;
- }
- break;
- case Js::OpCode::ProfiledStrictLdThis:
- newOpcode = Js::OpCode::StrictLdThis;
- if (m_func->HasProfileInfo())
- {
- dstOpnd->SetValueType(m_func->GetReadOnlyProfileInfo()->GetThisInfo().valueType);
- }
- if (m_func->DoSimpleJitDynamicProfile())
- {
- IR::JitProfilingInstr* newInstr = IR::JitProfilingInstr::New(Js::OpCode::StrictLdThis, dstOpnd, src1Opnd, m_func);
- instr = newInstr;
- }
- break;
- case Js::OpCode::Delete_A:
- dstOpnd->SetValueType(ValueType::Boolean);
- break;
- case Js::OpCode::BeginSwitch:
- m_switchBuilder.BeginSwitch();
- newOpcode = Js::OpCode::Ld_A;
- break;
- case Js::OpCode::LdArrHead:
- src1Opnd->SetValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(false).SetArrayTypeId(Js::TypeIds_Array));
- src1Opnd->SetValueTypeFixed();
- break;
- case Js::OpCode::LdInnerFrameDisplayNoParent:
- {
- instr = IR::Instr::New(Js::OpCode::LdInnerFrameDisplay, dstOpnd, src1Opnd, m_func);
- this->AddEnvOpndForInnerFrameDisplay(instr, offset);
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::Conv_Str:
- dstOpnd->SetValueType(ValueType::String);
- break;
- case Js::OpCode::Yield:
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- this->AddInstr(instr, offset);
- this->m_lastInstr = instr->ConvertToBailOutInstr(instr, IR::BailOutForGeneratorYield);
- IR::LabelInstr* label = IR::LabelInstr::New(Js::OpCode::Label, m_func);
- label->m_hasNonBranchRef = true;
- this->AddInstr(label, Js::Constants::NoByteCodeOffset);
- this->m_func->AddYieldOffsetResumeLabel(nextOffset, label);
- return;
- }
- if (instr == nullptr)
- {
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- }
- this->AddInstr(instr, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildProfiledReg2
- ///
- /// Build IR instr for a profiled Reg2 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledReg2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Reg2<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- }
- BuildProfiledReg2(newOpcode, offset, layout->R0, layout->R1, layout->profileId);
- }
- void
- IRBuilder::BuildProfiledReg2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, Js::ProfileId profileId)
- {
- bool switchFound = false;
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- Assert(newOpcode == Js::OpCode::BeginSwitch);
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(srcRegSlot);
- IR::RegOpnd * dstOpnd;
- if(srcRegSlot == dstRegSlot)
- {
- //if the operands are the same for BeginSwitch, don't build a new operand in IR.
- dstOpnd = src1Opnd;
- }
- else
- {
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- }
- m_switchBuilder.BeginSwitch();
- switchFound = true;
- newOpcode = Js::OpCode::Ld_A; // BeginSwitch is originally equivalent to Ld_A
- IR::Instr *instr;
- if (m_func->DoSimpleJitDynamicProfile())
- {
- // Since we're in simplejit, we want to keep track of the profileid:
- IR::JitProfilingInstr *profiledInstr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- profiledInstr->profileId = profileId;
- profiledInstr->isBeginSwitch = newOpcode == Js::OpCode::Ld_A;
- instr = profiledInstr;
- }
- else
- {
- IR::ProfiledInstr *profiledInstr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr = profiledInstr;
- profiledInstr->u.FldInfo() = Js::FldInfo();
- }
- this->AddInstr(instr, offset);
- if(switchFound && instr->IsProfiledInstr())
- {
- m_switchBuilder.SetProfiledInstruction(instr, profileId);
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg3
- ///
- /// Build IR instr for a Reg3 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg3(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func) && newOpcode != Js::OpCode::NewInnerScopeSlots)
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- }
- BuildReg3(newOpcode, offset, layout->R0, layout->R1, layout->R2, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledReg3(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Reg3<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- }
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- BuildReg3(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->profileId);
- }
- void
- IRBuilder::BuildReg3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
- Js::RegSlot src2RegSlot, Js::ProfileId profileId)
- {
- IR::Instr * instr;
- if (newOpcode == Js::OpCode::NewInnerScopeSlots)
- {
- if (dstRegSlot >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- newOpcode = Js::OpCode::NewScopeSlotsWithoutPropIds;
- dstRegSlot += m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
- instr = IR::Instr::New(newOpcode, BuildDstOpnd(dstRegSlot),
- IR::IntConstOpnd::New(src1RegSlot, TyVar, m_func),
- IR::IntConstOpnd::New(src2RegSlot, TyVar, m_func),
- m_func);
- if (instr->GetDst()->AsRegOpnd()->m_sym->m_isSingleDef)
- {
- instr->GetDst()->AsRegOpnd()->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
- IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- StackSym * dstSym = dstOpnd->m_sym;
- bool isProfiledInstr = (profileId != Js::Constants::NoProfileId);
- bool wasNotProfiled = false;
- const Js::LdElemInfo * ldElemInfo = nullptr;
- if (isProfiledInstr && newOpcode == Js::OpCode::IsIn)
- {
- if (!DoLoadInstructionArrayProfileInfo())
- {
- isProfiledInstr = false;
- }
- else
- {
- ldElemInfo = this->m_func->GetReadOnlyProfileInfo()->GetLdElemInfo(profileId);
- ValueType arrayType = ldElemInfo->GetArrayType();
- wasNotProfiled = !ldElemInfo->WasProfiled();
- if (arrayType.IsLikelyNativeArray() && !AllowNativeArrayProfileInfo())
- {
- arrayType = arrayType.SetArrayTypeId(Js::TypeIds_Array);
- // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the ProfiledInstr.
- Js::LdElemInfo *const newLdElemInfo = JitAnew(m_func->m_alloc, Js::LdElemInfo, *ldElemInfo);
- newLdElemInfo->arrayType = arrayType;
- ldElemInfo = newLdElemInfo;
- }
- src2Opnd->SetValueType(arrayType);
- if (m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry())
- {
- isProfiledInstr = false;
- }
- }
- }
- if (isProfiledInstr)
- {
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else
- {
- instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- if (newOpcode == Js::OpCode::IsIn)
- {
- instr->AsProfiledInstr()->u.ldElemInfo = ldElemInfo;
- }
- else
- {
- instr->AsProfiledInstr()->u.profileId = profileId;
- }
- }
- }
- else
- {
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- }
- this->AddInstr(instr, offset);
- if (wasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- switch (newOpcode)
- {
- case Js::OpCode::LdHandlerScope:
- case Js::OpCode::NewScopeSlotsWithoutPropIds:
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isNotNumber = true;
- }
- break;
- case Js::OpCode::LdInnerFrameDisplay:
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isNotNumber = true;
- }
- break;
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg3C
- ///
- /// Build IR instr for a Reg3C instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg3C(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3C<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- }
- BuildReg3C(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->inlineCacheIndex);
- }
- void
- IRBuilder::BuildReg3C(Js::OpCode newOpCode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
- Js::RegSlot src2RegSlot, Js::CacheId inlineCacheIndex)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpCode));
- IR::Instr * instr;
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
- IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(newOpCode, dstOpnd, IR::IntConstOpnd::New(inlineCacheIndex, TyUint32, m_func), instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg4
- ///
- /// Build IR instr for a Reg4 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg4(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg4<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- this->DoClosureRegCheck(layout->R3);
- }
- BuildReg4(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->R3);
- }
- void
- IRBuilder::BuildReg4(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
- Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot)
- {
- IR::Instr * instr;
- Assert(newOpcode == Js::OpCode::Concat3);
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
- IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
- IR::RegOpnd * src3Opnd = this->BuildSrcOpnd(src3RegSlot);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- IR::RegOpnd * str1Opnd = InsertConvPrimStr(src1Opnd, offset, true);
- IR::RegOpnd * str2Opnd = InsertConvPrimStr(src2Opnd, Js::Constants::NoByteCodeOffset, true);
- IR::RegOpnd * str3Opnd = InsertConvPrimStr(src3Opnd, Js::Constants::NoByteCodeOffset, true);
- // Need to insert a byte code use for src1/src2 that if ConvPrimStr of the src2/src3 bail out
- // we will restore it.
- bool src1HasByteCodeRegSlot = src1Opnd->m_sym->HasByteCodeRegSlot();
- bool src2HasByteCodeRegSlot = src2Opnd->m_sym->HasByteCodeRegSlot();
- if (src1HasByteCodeRegSlot || src2HasByteCodeRegSlot)
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, Js::Constants::NoByteCodeOffset);
- if (src1HasByteCodeRegSlot)
- {
- byteCodeUse->Set(src1Opnd);
- }
- if (src2HasByteCodeRegSlot)
- {
- byteCodeUse->Set(src2Opnd);
- }
- this->AddInstr(byteCodeUse, Js::Constants::NoByteCodeOffset);
- }
- if (!PHASE_OFF(Js::BackendConcatExprOptPhase, this->m_func))
- {
- IR::RegOpnd* tmpDstOpnd1 = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
- IR::RegOpnd* tmpDstOpnd2 = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
- IR::RegOpnd* tmpDstOpnd3 = IR::RegOpnd::New(StackSym::New(this->m_func), TyVar, this->m_func);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItemBE, tmpDstOpnd1, str1Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItemBE, tmpDstOpnd2, str2Opnd, tmpDstOpnd1, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItemBE, tmpDstOpnd3, str3Opnd, tmpDstOpnd2, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::IntConstOpnd * countIntConstOpnd = IR::IntConstOpnd::New(3, TyUint32, m_func, true);
- instr = IR::Instr::New(Js::OpCode::NewConcatStrMultiBE, dstOpnd, countIntConstOpnd, tmpDstOpnd3, m_func);
- dstOpnd->SetValueType(ValueType::String);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- else
- {
- instr = IR::Instr::New(Js::OpCode::NewConcatStrMulti, dstOpnd, IR::IntConstOpnd::New(3, TyUint32, m_func, true), m_func);
- dstOpnd->SetValueType(ValueType::String);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, IR::IndirOpnd::New(dstOpnd, 0, TyVar, m_func), str1Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, IR::IndirOpnd::New(dstOpnd, 1, TyVar, m_func), str2Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, IR::IndirOpnd::New(dstOpnd, 2, TyVar, m_func), str3Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- }
- IR::RegOpnd *
- IRBuilder::InsertConvPrimStr(IR::RegOpnd * srcOpnd, uint offset, bool forcePreOpBailOutIfNeeded)
- {
- IR::RegOpnd * strOpnd = IR::RegOpnd::New(TyVar, this->m_func);
- IR::Instr * instr = IR::Instr::New(Js::OpCode::Conv_PrimStr, strOpnd, srcOpnd, m_func);
- instr->forcePreOpBailOutIfNeeded = forcePreOpBailOutIfNeeded;
- strOpnd->SetValueType(ValueType::String);
- strOpnd->SetValueTypeFixed();
- this->AddInstr(instr, offset);
- return strOpnd;
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg2B1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2B1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- }
- BuildReg2B1(newOpcode, offset, layout->R0, layout->R1, layout->B2);
- }
- void
- IRBuilder::BuildReg2B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, byte index)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- Assert(newOpcode == Js::OpCode::SetConcatStrMultiItem);
- IR::Instr * instr;
- IR::RegOpnd * srcOpnd = this->BuildSrcOpnd(srcRegSlot);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- IR::IndirOpnd * indir1Opnd = IR::IndirOpnd::New(dstOpnd, index, TyVar, m_func);
- dstOpnd->SetValueType(ValueType::String);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, indir1Opnd, InsertConvPrimStr(srcOpnd, offset, true), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg3B1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg3B1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- }
- BuildReg3B1(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->B3);
- }
- void
- IRBuilder::BuildReg3B1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
- Js::RegSlot src2RegSlot, uint8 index)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(src1RegSlot);
- IR::RegOpnd * src2Opnd = this->BuildSrcOpnd(src2RegSlot);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- dstOpnd->SetValueType(ValueType::String);
- IR::Instr * newConcatStrMulti = nullptr;
- switch (newOpcode)
- {
- case Js::OpCode::NewConcatStrMulti:
- newConcatStrMulti = IR::Instr::New(Js::OpCode::NewConcatStrMulti, dstOpnd, IR::IntConstOpnd::New(index, TyUint32, m_func), m_func);
- index = 0;
- break;
- case Js::OpCode::SetConcatStrMultiItem2:
- break;
- default:
- Assert(false);
- };
- IR::IndirOpnd * indir1Opnd = IR::IndirOpnd::New(dstOpnd, index, TyVar, m_func);
- IR::IndirOpnd * indir2Opnd = IR::IndirOpnd::New(dstOpnd, index + 1, TyVar, m_func);
- // Need to do the to str first, as they may have side effects.
- IR::RegOpnd * str1Opnd = InsertConvPrimStr(src1Opnd, offset, true);
- IR::RegOpnd * str2Opnd = InsertConvPrimStr(src2Opnd, Js::Constants::NoByteCodeOffset, true);
- // Need to insert a byte code use for src1 so that if ConvPrimStr of the src2 bail out
- // we will restore it.
- if (src1Opnd->m_sym->HasByteCodeRegSlot())
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, Js::Constants::NoByteCodeOffset);
- byteCodeUse->Set(src1Opnd);
- this->AddInstr(byteCodeUse, Js::Constants::NoByteCodeOffset);
- }
- if (newConcatStrMulti)
- {
- // Allocate the concat str after the ConvToStr
- this->AddInstr(newConcatStrMulti, Js::Constants::NoByteCodeOffset);
- }
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, indir1Opnd, str1Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::SetConcatStrMultiItem, indir2Opnd, str2Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg5
- ///
- /// Build IR instr for a Reg5 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg5(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg5<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- this->DoClosureRegCheck(layout->R3);
- this->DoClosureRegCheck(layout->R4);
- }
- BuildReg5(newOpcode, offset, layout->R0, layout->R1, layout->R2, layout->R3, layout->R4);
- }
- void
- IRBuilder::BuildReg5(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot src1RegSlot,
- Js::RegSlot src2RegSlot, Js::RegSlot src3RegSlot, Js::RegSlot src4RegSlot)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- IR::RegOpnd * dstOpnd;
- IR::RegOpnd * src1Opnd;
- IR::RegOpnd * src2Opnd;
- IR::RegOpnd * src3Opnd;
- IR::RegOpnd * src4Opnd;
- // We can't support instructions with more than 2 srcs. Instead create a CallHelper instructions,
- // and pass the srcs as ArgOut_A instructions.
- src1Opnd = this->BuildSrcOpnd(src1RegSlot);
- src2Opnd = this->BuildSrcOpnd(src2RegSlot);
- src3Opnd = this->BuildSrcOpnd(src3RegSlot);
- src4Opnd = this->BuildSrcOpnd(src4RegSlot);
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src4Opnd, m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::HelperCallOpnd *helperOpnd;
- switch (newOpcode) {
- case Js::OpCode::ApplyArgs:
- helperOpnd=IR::HelperCallOpnd::New(IR::HelperOp_OP_ApplyArgs, this->m_func);
- break;
- default:
- AssertMsg(UNREACHED, "Unknown Reg5 opcode");
- Fatal();
- }
- instr = IR::Instr::New(Js::OpCode::CallHelper, dstOpnd, helperOpnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- void
- IRBuilder::BuildW1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- unsigned short C1;
- const unaligned Js::OpLayoutW1 *regLayout = m_jnReader.W1();
- C1 = regLayout->C1;
- IR::Instr * instr;
- IntConstType value = C1;
- IR::IntConstOpnd * srcOpnd;
- srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
- instr = IR::Instr::New(newOpcode, m_func);
- instr->SetSrc1(srcOpnd);
- this->AddInstr(instr, offset);
- if (newOpcode == Js::OpCode::RuntimeReferenceError || newOpcode == Js::OpCode::RuntimeTypeError)
- {
- if (DoBailOnNoProfile())
- {
- // RuntimeReferenceError are extremely rare as they are guaranteed to throw. Insert BailonNoProfile to optimize this code path.
- // If there are continues bailout bailonnoprofile will be disabled.
- InsertBailOnNoProfile(instr);
- }
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildUnsigned1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Unsigned1<SizePolicy>>();
- BuildUnsigned1(newOpcode, offset, layout->C1);
- }
- void
- IRBuilder::BuildUnsigned1(Js::OpCode newOpcode, uint32 offset, uint32 num)
- {
- switch (newOpcode)
- {
- case Js::OpCode::EmitTmpRegCount:
- // Note: EmitTmpRegCount is inserted when debugging, not needed for jit.
- // It's only needed by the debugger to see how many tmp regs are active.
- Assert(m_func->IsJitInDebugMode());
- return;
- case Js::OpCode::NewBlockScope:
- case Js::OpCode::NewPseudoScope:
- {
- if (num >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- Js::RegSlot dstRegSlot = num + m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
- IR::RegOpnd * dstOpnd = BuildDstOpnd(dstRegSlot);
- IR::Instr * instr = IR::Instr::New(newOpcode, dstOpnd, m_func);
- this->AddInstr(instr, offset);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- break;
- }
- case Js::OpCode::CloneInnerScopeSlots:
- case Js::OpCode::CloneBlockScope:
- {
- if (num >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- Js::RegSlot srcRegSlot = num + m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
- IR::RegOpnd * srcOpnd = BuildSrcOpnd(srcRegSlot);
- IR::Instr * instr = IR::Instr::New(newOpcode, m_func);
- instr->SetSrc1(srcOpnd);
- this->AddInstr(instr, offset);
- break;
- }
- case Js::OpCode::ProfiledLoopBodyStart:
- {
- // This opcode is removed from the IR when we aren't doing Profiling SimpleJit or not jitting loop bodies
- if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
- {
- // Attach a register to the dest of this instruction to communicate whether we should bail out (the deciding of this is done in lowering)
- IR::Opnd* fullJitExists = IR::RegOpnd::New(TyUint8, m_func);
- auto start = m_lastInstr;
- if (start->m_opcode == Js::OpCode::InitLoopBodyCount)
- {
- Assert(this->IsLoopBody());
- start = start->m_prev;
- }
- Assert(start->m_opcode == Js::OpCode::ProfiledLoopStart && start->GetDst());
- IR::JitProfilingInstr* instr = IR::JitProfilingInstr::New(Js::OpCode::ProfiledLoopBodyStart, fullJitExists, start->GetDst(), m_func);
- // profileId is used here to represent the loop number
- instr->loopNumber = num;
- this->AddInstr(instr, offset);
- // If fullJitExists isn't 0, bail out so that we can get the fulljitted version
- BailOutInfo * bailOutInfo = JitAnew(m_func->m_alloc, BailOutInfo, instr->GetByteCodeOffset(), m_func);
- IR::BailOutInstr * bailInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, IR::BailOnSimpleJitToFullJitLoopBody, bailOutInfo, bailOutInfo->bailOutFunc);
- bailInstr->SetSrc1(fullJitExists);
- bailInstr->SetSrc2(IR::IntConstOpnd::New(0, TyUint8, m_func, true));
- this->AddInstr(bailInstr, offset);
- }
- Js::ImplicitCallFlags flags = Js::ImplicitCall_HasNoInfo;
- Js::LoopFlags loopFlags;
- if (this->m_func->HasProfileInfo())
- {
- flags = m_func->GetReadOnlyProfileInfo()->GetLoopImplicitCallFlags(num);
- loopFlags = m_func->GetReadOnlyProfileInfo()->GetLoopFlags(num);
- }
- // Put a label the instruction stream to carry the profile info
- IR::ProfiledLabelInstr * labelInstr = IR::ProfiledLabelInstr::New(Js::OpCode::Label, this->m_func, flags, loopFlags);
- #if DBG
- labelInstr->loopNum = num;
- #endif
- m_lastInstr->InsertAfter(labelInstr);
- m_lastInstr = labelInstr;
- // Set it to the offset to the start of the loop
- labelInstr->SetByteCodeOffset(m_jnReader.GetCurrentOffset());
- break;
- }
- case Js::OpCode::LoopBodyStart:
- break;
- case Js::OpCode::ProfiledLoopStart:
- {
- AssertOrFailFast(num < m_func->GetJITFunctionBody()->GetLoopCount());
- // If we're in profiling SimpleJit and jitting loop bodies, we need to keep this until lowering.
- if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
- {
- // In order for the JIT engine to correctly allocate registers we need to have this set up before lowering.
- // There may be 0 to many LoopEnds, but there will only ever be one LoopStart
- Assert(!this->m_saveLoopImplicitCallFlags[num]);
- const auto ty = Lowerer::GetImplicitCallFlagsType();
- auto saveOpnd = IR::RegOpnd::New(ty, m_func);
- this->m_saveLoopImplicitCallFlags[num] = saveOpnd;
- // Note that we insert this instruction /before/ the actual ProfiledLoopStart opcode. This is because Lowering is backwards
- // and this is just a fake instruction which is only used to pass on the saveOpnd; this instruction will eventually be removed.
- auto instr = IR::JitProfilingInstr::New(Js::OpCode::Ld_A, saveOpnd, IR::MemRefOpnd::New((intptr_t)0, ty, m_func), m_func);
- instr->isLoopHelper = true;
- this->AddInstr(instr, offset);
- instr = IR::JitProfilingInstr::New(Js::OpCode::ProfiledLoopStart, IR::RegOpnd::New(TyMachPtr, m_func), nullptr, m_func);
- instr->loopNumber = num;
- this->AddInstr(instr, offset);
- }
- if (this->IsLoopBody() && !m_loopCounterSym)
- {
- InsertInitLoopBodyLoopCounter(num);
- }
- break;
- }
- case Js::OpCode::ProfiledLoopEnd:
- {
- AssertOrFailFast(num < m_func->GetJITFunctionBody()->GetLoopCount());
- // TODO: Decide whether we want the implicit loop call flags to be recorded in simplejitted loop bodies
- if (m_func->DoSimpleJitDynamicProfile() && m_func->GetJITFunctionBody()->DoJITLoopBody())
- {
- Assert(this->m_saveLoopImplicitCallFlags[num]);
- // In profiling simplejit we need this opcode in order to restore the implicit call flags
- auto instr = IR::JitProfilingInstr::New(Js::OpCode::ProfiledLoopEnd, nullptr, this->m_saveLoopImplicitCallFlags[num], m_func);
- this->AddInstr(instr, offset);
- instr->loopNumber = num;
- }
- if (!this->IsLoopBody())
- {
- break;
- }
- // In the early exit case (return), we generated ProfiledLoopEnd for all the outer loop.
- // If we see one of these profile loop, just load the IP of the immediate outer loop of the loop body being JIT'ed
- // and then skip all the other loops using the fact that we have already loaded the return IP
- if (IsLoopBodyReturnIPInstr(m_lastInstr))
- {
- // Already loaded the loop IP sym, skip
- break;
- }
- // See we are ending an outer loop and load the return IP to the ProfiledLoopEnd opcode
- // instead of following the normal branch
- const JITLoopHeaderIDL * loopHeader = m_func->GetJITFunctionBody()->GetLoopHeaderData(num);
- if (m_func->GetJITFunctionBody()->GetLoopHeaderAddr(num) != m_func->m_workItem->GetLoopHeaderAddr() &&
- JITTimeFunctionBody::LoopContains(loopHeader, m_func->m_workItem->GetLoopHeader()))
- {
- this->InsertLoopBodyReturnIPInstr(offset, offset);
- }
- else
- {
- Assert(JITTimeFunctionBody::LoopContains(m_func->m_workItem->GetLoopHeader(), loopHeader));
- }
- break;
- }
- case Js::OpCode::InvalCachedScope:
- {
- // The reg and constant are both src operands.
- IR::Instr* instr = IR::Instr::New(Js::OpCode::InvalCachedScope, m_func);
- IR::RegOpnd *envOpnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetEnvReg());
- instr->SetSrc1(envOpnd);
- IR::IntConstOpnd *envIndex = IR::IntConstOpnd::New(num, TyInt32, m_func, true);
- instr->SetSrc2(envIndex);
- this->AddInstr(instr, offset);
- return;
- }
- default:
- Assert(false);
- __assume(false);
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledReg1Unsigned1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Reg1Unsigned1<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- }
- BuildProfiledReg1Unsigned1(newOpcode, offset, layout->R0, layout->C1, layout->profileId);
- }
- void
- IRBuilder::BuildProfiledReg1Unsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot R0, int32 C1, Js::ProfileId profileId)
- {
- Assert(newOpcode == Js::OpCode::ProfiledNewScArray || newOpcode == Js::OpCode::ProfiledInitForInEnumerator);
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- if (newOpcode == Js::OpCode::InitForInEnumerator)
- {
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(R0);
- IR::Opnd * src2Opnd = this->BuildForInEnumeratorOpnd(C1);
- IR::Instr *instr = IR::ProfiledInstr::New(Js::OpCode::InitForInEnumerator, nullptr, src1Opnd, src2Opnd, m_func);
- instr->AsProfiledInstr()->u.profileId = profileId;
- this->AddInstr(instr, offset);
- return;
- }
- IR::Instr *instr;
- Js::RegSlot dstRegSlot = R0;
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- StackSym * dstSym = dstOpnd->m_sym;
- int32 value = C1;
- IR::IntConstOpnd * srcOpnd;
- srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else
- {
- instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- instr->AsProfiledInstr()->u.profileId = profileId;
- }
- this->AddInstr(instr, offset);
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isSafeThis = true;
- dstSym->m_isNotNumber = true;
- }
- // Undefined values in array literals ([0, undefined, 1]) are treated as missing values in some versions
- Js::ArrayCallSiteInfo *arrayInfo = nullptr;
- if (m_func->HasArrayInfo())
- {
- arrayInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId);
- }
- Js::TypeId arrayTypeId = Js::TypeIds_Array;
- if (arrayInfo && !m_func->IsJitInDebugMode() && Js::JavascriptArray::HasInlineHeadSegment(value))
- {
- if (arrayInfo->IsNativeIntArray())
- {
- arrayTypeId = Js::TypeIds_NativeIntArray;
- }
- else if (arrayInfo->IsNativeFloatArray())
- {
- arrayTypeId = Js::TypeIds_NativeFloatArray;
- }
- }
- dstOpnd->SetValueType(ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
- if (dstOpnd->GetValueType().HasVarElements())
- {
- dstOpnd->SetValueTypeFixed();
- }
- else
- {
- dstOpnd->SetValueType(dstOpnd->GetValueType().ToLikely());
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg1Unsigned1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg1Unsigned1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- }
- BuildReg1Unsigned1(newOpcode, offset, layout->R0, layout->C1);
- }
- void
- IRBuilder::BuildReg1Unsigned1(Js::OpCode newOpcode, uint offset, Js::RegSlot R0, int32 C1)
- {
- switch (newOpcode)
- {
- case Js::OpCode::NewRegEx:
- this->BuildRegexFromPattern(R0, C1, offset);
- return;
- case Js::OpCode::LdInnerScope:
- {
- IR::RegOpnd * srcOpnd = BuildSrcOpnd(this->InnerScopeIndexToRegSlot(C1));
- IR::RegOpnd * dstOpnd = BuildDstOpnd(R0);
- IR::Instr * instr = IR::Instr::New(Js::OpCode::Ld_A, dstOpnd, srcOpnd, m_func);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::LdIndexedFrameDisplayNoParent:
- {
- newOpcode = Js::OpCode::LdFrameDisplay;
- IR::RegOpnd *srcOpnd = this->BuildSrcOpnd(this->InnerScopeIndexToRegSlot(C1));
- IR::RegOpnd *dstOpnd = this->BuildDstOpnd(R0);
- IR::Instr *instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- this->AddEnvOpndForInnerFrameDisplay(instr, offset);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::GetCachedFunc:
- {
- IR::RegOpnd *src1Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
- IR::Opnd *src2Opnd = IR::IntConstOpnd::New(C1, TyUint32, m_func);
- IR::RegOpnd *dstOpnd = this->BuildDstOpnd(R0);
- IR::Instr *instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::InitForInEnumerator:
- {
- IR::Instr *instr = IR::Instr::New(Js::OpCode::InitForInEnumerator, m_func);
- instr->SetSrc1(this->BuildSrcOpnd(R0));
- instr->SetSrc2(this->BuildForInEnumeratorOpnd(C1));
- this->AddInstr(instr, offset);
- return;
- }
- }
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(R0);
- StackSym * dstSym = dstOpnd->m_sym;
- IntConstType value = C1;
- IR::IntConstOpnd * srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
- IR::Instr * instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- this->AddInstr(instr, offset);
- if (newOpcode == Js::OpCode::NewScopeSlots)
- {
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::Ld_A, IR::RegOpnd::New(m_func->GetLocalClosureSym(), TyVar, m_func), dstOpnd, m_func),
- (uint32)-1);
- }
- if (dstSym->m_isSingleDef)
- {
- switch (newOpcode)
- {
- case Js::OpCode::NewScArray:
- case Js::OpCode::NewScArrayWithMissingValues:
- dstSym->m_isSafeThis = true;
- dstSym->m_isNotNumber = true;
- break;
- }
- }
- if (newOpcode == Js::OpCode::NewScArray || newOpcode == Js::OpCode::NewScArrayWithMissingValues)
- {
- // Undefined values in array literals ([0, undefined, 1]) are treated as missing values in some versions
- dstOpnd->SetValueType(
- ValueType::GetObject(ObjectType::Array)
- .SetHasNoMissingValues(newOpcode == Js::OpCode::NewScArray)
- .SetArrayTypeId(Js::TypeIds_Array));
- dstOpnd->SetValueTypeFixed();
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg2Int1
- ///
- /// Build IR instr for a Reg2I4 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildReg2Int1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Reg2Int1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R0);
- this->DoClosureRegCheck(layout->R1);
- }
- BuildReg2Int1(newOpcode, offset, layout->R0, layout->R1, layout->C1);
- }
- void
- IRBuilder::BuildReg2Int1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot dstRegSlot, Js::RegSlot srcRegSlot, int32 value)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- if (newOpcode == Js::OpCode::LdIndexedFrameDisplay)
- {
- newOpcode = Js::OpCode::LdFrameDisplay;
- if ((uint)value >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- IR::RegOpnd *src1Opnd = this->BuildSrcOpnd(value + m_func->GetJITFunctionBody()->GetFirstInnerScopeReg());
- IR::RegOpnd *src2Opnd = this->BuildSrcOpnd(srcRegSlot);
- IR::RegOpnd *dstOpnd = this->BuildDstOpnd(dstRegSlot);
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(srcRegSlot);
- IR::IntConstOpnd * src2Opnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(dstRegSlot);
- switch (newOpcode)
- {
- case Js::OpCode::ProfiledLdThis:
- newOpcode = Js::OpCode::LdThis;
- if(m_func->HasProfileInfo())
- {
- dstOpnd->SetValueType(m_func->GetReadOnlyProfileInfo()->GetThisInfo().valueType);
- }
- if(m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- // Break out since we just made the instr
- break;
- }
- // fall-through
- default:
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, src2Opnd, m_func);
- break;
- }
- this->AddInstr(instr, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementC
- ///
- /// Build IR instr for an ElementC instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementScopedC(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementScopedC<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- BuildElementScopedC(newOpcode, offset, layout->Value, layout->PropertyIdIndex);
- }
- void
- IRBuilder::BuildElementScopedC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
- {
- IR::Instr * instr;
- Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
- PropertyKind propertyKind = PropertyKindData;
- IR::RegOpnd * regOpnd;
- Js::RegSlot fieldRegSlot = this->GetEnvRegForEvalCode();
- IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, propertyId, propertyIdIndex, propertyKind);
- switch (newOpcode)
- {
- case Js::OpCode::ScopedEnsureNoRedeclFld:
- {
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
- break;
- }
- case Js::OpCode::ScopedDeleteFld:
- case Js::OpCode::ScopedDeleteFldStrict:
- {
- Assert(this->m_func->GetScriptContextInfo()->GetAddr() == this->m_func->GetTopFunc()->GetScriptContextInfo()->GetAddr());
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- break;
- }
- case Js::OpCode::ScopedInitFunc:
- {
- // Implicit root object as default instance
- IR::Opnd * instance2Opnd = this->BuildSrcOpnd(Js::FunctionBody::RootObjectRegSlot);
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, instance2Opnd, m_func);
- break;
- }
- default:
- AssertMsg(UNREACHED, "Unknown ElementScopedC opcode");
- Fatal();
- }
- this->AddInstr(instr, offset);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementC(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementC<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildElementC(newOpcode, offset, layout->Instance, layout->Value, layout->PropertyIdIndex);
- }
- void
- IRBuilder::BuildElementC(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
- {
- IR::Instr * instr;
- Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
- PropertyKind propertyKind = PropertyKindData;
- IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, propertyId, propertyIdIndex, propertyKind);
- IR::RegOpnd * regOpnd;
- switch (newOpcode)
- {
- case Js::OpCode::DeleteFld:
- case Js::OpCode::DeleteRootFld:
- case Js::OpCode::DeleteFldStrict:
- case Js::OpCode::DeleteRootFldStrict:
- // Load
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- break;
- case Js::OpCode::InitSetFld:
- case Js::OpCode::InitGetFld:
- case Js::OpCode::InitClassMemberGet:
- case Js::OpCode::InitClassMemberSet:
- case Js::OpCode::InitProto:
- case Js::OpCode::StFuncExpr:
- // Store
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
- break;
- default:
- AssertMsg(UNREACHED, "Unknown ElementC opcode");
- Fatal();
- }
- this->AddInstr(instr, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementSlot
- ///
- /// Build IR instr for an ElementSlot instruction.
- ///
- ///----------------------------------------------------------------------------
- IR::Instr *
- IRBuilder::BuildProfiledSlotLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::ProfileId profileId, bool *pUnprofiled)
- {
- IR::Instr * instr = nullptr;
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else if(this->m_func->HasProfileInfo())
- {
- instr = IR::ProfiledInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
- instr->AsProfiledInstr()->u.FldInfo().valueType =
- this->m_func->GetReadOnlyProfileInfo()->GetSlotLoad(profileId);
- *pUnprofiled = instr->AsProfiledInstr()->u.FldInfo().valueType.IsUninitialized();
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if(Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::DynamicProfilePhase))
- {
- const ValueType valueType(instr->AsProfiledInstr()->u.FldInfo().valueType);
- char valueTypeStr[VALUE_TYPE_MAX_STRING_SIZE];
- valueType.ToString(valueTypeStr);
- char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
- Output::Print(_u("TestTrace function %s (#%s) ValueType = %S "), m_func->GetJITFunctionBody()->GetDisplayName(), m_func->GetDebugNumberSet(debugStringBuffer), valueTypeStr);
- instr->DumpTestTrace();
- }
- #endif
- }
- return instr;
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementSlot(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlot<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildElementSlot(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledElementSlot(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlot<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- }
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- BuildElementSlot(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, layout->profileId);
- }
- void
- IRBuilder::BuildElementSlot(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
- int32 slotId, Js::ProfileId profileId)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- IR::RegOpnd * regOpnd;
- IR::SymOpnd * fieldSymOpnd;
- PropertyKind propertyKind = PropertyKindSlots;
- PropertySym * fieldSym;
- StackSym * stackFuncPtrSym = nullptr;
- bool isLdSlotThatWasNotProfiled = false;
- switch (newOpcode)
- {
- case Js::OpCode::NewInnerStackScFunc:
- stackFuncPtrSym = this->EnsureStackFuncPtrSym();
- // fall through
- case Js::OpCode::NewInnerScFunc:
- newOpcode = Js::OpCode::NewScFunc;
- goto NewScFuncCommon;
- case Js::OpCode::NewInnerScGenFunc:
- newOpcode = Js::OpCode::NewScGenFunc;
- NewScFuncCommon:
- {
- IR::Opnd * functionBodySlotOpnd = IR::IntConstOpnd::New(slotId, TyInt32, m_func, true);
- IR::Opnd * environmentOpnd = this->BuildSrcOpnd(fieldRegSlot);
- regOpnd = this->BuildDstOpnd(regSlot);
- if (stackFuncPtrSym)
- {
- IR::RegOpnd * dataOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::NewScFuncData, dataOpnd, environmentOpnd, IR::RegOpnd::New(stackFuncPtrSym, TyVar, m_func), m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, dataOpnd, m_func);
- }
- else
- {
- instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, environmentOpnd, m_func);
- }
- if (regOpnd->m_sym->m_isSingleDef)
- {
- regOpnd->m_sym->m_isSafeThis = true;
- regOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::NewScFuncHomeObj:
- case Js::OpCode::NewScGenFuncHomeObj:
- {
- Js::FunctionInfoPtrPtr infoRef = m_func->GetJITFunctionBody()->GetNestedFuncRef(slotId);
- IR::AddrOpnd * functionBodySlotOpnd = IR::AddrOpnd::New((Js::Var)infoRef, IR::AddrOpndKindDynamicMisc, m_func);
- IR::Opnd * environmentOpnd = GetEnvironmentOperand(offset);
- IR::Opnd * homeObjOpnd = this->BuildSrcOpnd(fieldRegSlot);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), homeObjOpnd, m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), functionBodySlotOpnd, instr->GetDst(), m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), environmentOpnd, instr->GetDst(), m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(newOpcode, regOpnd, instr->GetDst(), m_func);
- if (regOpnd->m_sym->m_isSingleDef)
- {
- regOpnd->m_sym->m_isSafeThis = true;
- regOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- case Js::OpCode::LdObjSlot:
- newOpcode = Js::OpCode::LdSlot;
- goto ObjSlotCommon;
- case Js::OpCode::StObjSlot:
- newOpcode = Js::OpCode::StSlot;
- goto ObjSlotCommon;
- case Js::OpCode::StObjSlotChkUndecl:
- newOpcode = Js::OpCode::StSlotChkUndecl;
- ObjSlotCommon:
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldSymOpnd, m_func);
- this->AddInstr(instr, offset);
- fieldSym = PropertySym::New(regOpnd->m_sym, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldSymOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- if (newOpcode == Js::OpCode::StSlot || newOpcode == Js::OpCode::StSlotChkUndecl)
- {
- goto StSlotCommon;
- }
- goto LdSlotCommon;
- case Js::OpCode::LdSlotArr:
- propertyKind = PropertyKindSlotArray;
- case Js::OpCode::LdSlot:
- // Load
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, slotId, (Js::PropertyIdIndexType)-1, propertyKind);
- LdSlotCommon:
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = nullptr;
- if (profileId != Js::Constants::NoProfileId)
- {
- instr = this->BuildProfiledSlotLoad(newOpcode, regOpnd, fieldSymOpnd, profileId, &isLdSlotThatWasNotProfiled);
- }
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- }
- break;
- case Js::OpCode::StSlot:
- case Js::OpCode::StSlotChkUndecl:
- // Store
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, fieldRegSlot, slotId, (Js::PropertyIdIndexType)-1, propertyKind);
- StSlotCommon:
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
- if (newOpcode == Js::OpCode::StSlotChkUndecl)
- {
- // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
- instr->SetSrc2(fieldSymOpnd);
- }
- break;
- default:
- AssertMsg(UNREACHED, "Unknown ElementSlot opcode");
- Fatal();
- }
- this->AddInstr(instr, offset);
- if(isLdSlotThatWasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlotI1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- BuildElementSlotI1(newOpcode, offset, layout->Value, layout->SlotIndex, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledElementSlotI1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlotI1<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- BuildElementSlotI1(newOpcode, offset, layout->Value, layout->SlotIndex, layout->profileId);
- }
- void
- IRBuilder::BuildElementSlotI1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
- int32 slotId, Js::ProfileId profileId)
- {
- IR::RegOpnd *regOpnd;
- IR::SymOpnd *fieldOpnd;
- IR::Instr *instr = nullptr;
- IR::ByteCodeUsesInstr *byteCodeUse;
- PropertySym *fieldSym = nullptr;
- StackSym * stackFuncPtrSym = nullptr;
- SymID symID = m_func->GetJITFunctionBody()->GetLocalClosureReg();
- bool isLdSlotThatWasNotProfiled = false;
- StackSym* closureSym = m_func->GetLocalClosureSym();
- uint scopeSlotSize = this->IsParamScopeDone() ? m_func->GetJITFunctionBody()->GetScopeSlotArraySize() : m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
- switch (newOpcode)
- {
- case Js::OpCode::LdParamSlot:
- scopeSlotSize = m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
- closureSym = m_func->GetParamClosureSym();
- symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
- // Fall through
- case Js::OpCode::LdLocalSlot:
- if (!PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
- {
- if ((uint32)slotId >= scopeSlotSize + Js::ScopeSlots::FirstSlotIndex)
- {
- Js::Throw::FatalInternalError();
- }
- }
- if (closureSym->HasByteCodeRegSlot())
- {
- byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- // Read the scope slot pointer back using the stack closure sym.
- newOpcode = Js::OpCode::LdSlot;
- if (m_func->DoStackFrameDisplay())
- {
- // Read the scope slot pointer back using the stack closure sym.
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- symID = regOpnd->m_sym->m_id;
- if (IsLoopBody())
- {
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, slotId, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- // Need a dynamic check on the size of the local slot array.
- m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
- }
- }
- else if (IsLoopBody())
- {
- this->EnsureLoopBodyLoadSlot(symID);
- }
- fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = nullptr;
- if (profileId != Js::Constants::NoProfileId)
- {
- instr = this->BuildProfiledSlotLoad(Js::OpCode::LdSlot, regOpnd, fieldOpnd, profileId, &isLdSlotThatWasNotProfiled);
- }
- if (!instr)
- {
- instr = IR::Instr::New(Js::OpCode::LdSlot, regOpnd, fieldOpnd, m_func);
- }
- this->AddInstr(instr, offset);
- if (!m_func->DoStackFrameDisplay() && IsLoopBody())
- {
- // Need a dynamic check on the size of the local slot array.
- m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
- }
- break;
- case Js::OpCode::LdParamObjSlot:
- closureSym = m_func->GetParamClosureSym();
- symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
- newOpcode = Js::OpCode::LdLocalObjSlot;
- // Fall through
- case Js::OpCode::LdLocalObjSlot:
- if (closureSym->HasByteCodeRegSlot())
- {
- byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- fieldOpnd = this->BuildFieldOpnd(newOpcode, symID, (Js::DynamicObject::GetOffsetOfAuxSlots()) / sizeof(Js::Var), (Js::PropertyIdIndexType) - 1, PropertyKindSlotArray);
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- fieldSym = PropertySym::New(regOpnd->m_sym, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = nullptr;
- newOpcode = Js::OpCode::LdSlot;
- if (profileId != Js::Constants::NoProfileId)
- {
- instr = this->BuildProfiledSlotLoad(newOpcode, regOpnd, fieldOpnd, profileId, &isLdSlotThatWasNotProfiled);
- }
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, regOpnd, fieldOpnd, m_func);
- }
- this->AddInstr(instr, offset);
- break;
- case Js::OpCode::StParamSlot:
- case Js::OpCode::StParamSlotChkUndecl:
- scopeSlotSize = m_func->GetJITFunctionBody()->GetParamScopeSlotArraySize();
- closureSym = m_func->GetParamClosureSym();
- symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
- newOpcode = newOpcode == Js::OpCode::StParamSlot ? Js::OpCode::StLocalSlot : Js::OpCode::StLocalSlotChkUndecl;
- // Fall through
- case Js::OpCode::StLocalSlot:
- case Js::OpCode::StLocalSlotChkUndecl:
- if (!PHASE_OFF(Js::ClosureRangeCheckPhase, m_func))
- {
- if ((uint32)slotId >= scopeSlotSize + Js::ScopeSlots::FirstSlotIndex)
- {
- Js::Throw::FatalInternalError();
- }
- }
- if (closureSym->HasByteCodeRegSlot())
- {
- byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- newOpcode = newOpcode == Js::OpCode::StLocalSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
- if (m_func->DoStackFrameDisplay())
- {
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- // Read the scope slot pointer back using the stack closure sym.
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, 0, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- symID = regOpnd->m_sym->m_id;
- if (IsLoopBody())
- {
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, closureSym->m_id, slotId, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- // Need a dynamic check on the size of the local slot array.
- m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
- }
- }
- else
- {
- if (IsLoopBody())
- {
- this->EnsureLoopBodyLoadSlot(symID);
- }
- }
- fieldSym = PropertySym::FindOrCreate(symID, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
- this->AddInstr(instr, offset);
- if (newOpcode == Js::OpCode::StSlotChkUndecl)
- {
- instr->SetSrc2(fieldOpnd);
- }
- if (!m_func->DoStackFrameDisplay() && IsLoopBody())
- {
- // Need a dynamic check on the size of the local slot array.
- m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
- }
- break;
- case Js::OpCode::StParamObjSlot:
- case Js::OpCode::StParamObjSlotChkUndecl:
- closureSym = m_func->GetParamClosureSym();
- symID = m_func->GetJITFunctionBody()->GetParamClosureReg();
- newOpcode = newOpcode == Js::OpCode::StParamObjSlot ? Js::OpCode::StLocalObjSlot : Js::OpCode::StLocalObjSlotChkUndecl;
- // Fall through
- case Js::OpCode::StLocalObjSlot:
- case Js::OpCode::StLocalObjSlotChkUndecl:
- if (closureSym->HasByteCodeRegSlot())
- {
- byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(closureSym->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, symID, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- newOpcode = newOpcode == Js::OpCode::StLocalObjSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
- fieldSym = PropertySym::New(regOpnd->m_sym, slotId, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
- if (newOpcode == Js::OpCode::StSlotChkUndecl)
- {
- // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
- instr->SetSrc2(fieldOpnd);
- }
- this->AddInstr(instr, offset);
- break;
- case Js::OpCode::LdEnvObj:
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- m_func->GetTopFunc()->AddFrameDisplayCheck(fieldOpnd);
- break;
- case Js::OpCode::NewStackScFunc:
- stackFuncPtrSym = this->EnsureStackFuncPtrSym();
- newOpcode = Js::OpCode::NewScFunc;
- // fall through
- case Js::OpCode::NewScFunc:
- goto NewScFuncCommon;
- case Js::OpCode::NewScGenFunc:
- newOpcode = Js::OpCode::NewScGenFunc;
- NewScFuncCommon:
- {
- IR::Opnd * functionBodySlotOpnd = IR::IntConstOpnd::New(slotId, TyInt32, m_func, true);
- IR::Opnd *environmentOpnd = GetEnvironmentOperand(offset);
- regOpnd = this->BuildDstOpnd(regSlot);
- if (stackFuncPtrSym)
- {
- IR::RegOpnd * dataOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::NewScFuncData, dataOpnd, environmentOpnd,
- IR::RegOpnd::New(stackFuncPtrSym, TyVar, m_func), m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, dataOpnd, m_func);
- }
- else
- {
- instr = IR::Instr::New(newOpcode, regOpnd, functionBodySlotOpnd, environmentOpnd, m_func);
- }
- if (regOpnd->m_sym->m_isSingleDef)
- {
- regOpnd->m_sym->m_isSafeThis = true;
- regOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- default:
- Assert(0);
- }
- if(isLdSlotThatWasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- }
- IR::Opnd*
- IRBuilder::GetEnvironmentOperand(uint32 offset)
- {
- StackSym* sym = nullptr;
- // The byte code doesn't refer directly to a closure environment. Get the implicit one
- // that's pointed to by the function body.
- if (m_func->DoStackFrameDisplay() && m_func->GetLocalFrameDisplaySym())
- {
- // Read the scope slot pointer back using the stack closure sym.
- IR::Opnd *fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, m_func->GetLocalFrameDisplaySym()->m_id, 0, (Js::PropertyIdIndexType) - 1, PropertyKindSlotArray);
- IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, m_func);
- this->AddInstr(
- IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func),
- offset);
- sym = regOpnd->m_sym;
- }
- else
- {
- SymID symID;
- symID = this->GetEnvRegForInnerFrameDisplay();
- Assert(symID != Js::Constants::NoRegister);
- if (IsLoopBody() && !RegIsConstant(symID))
- {
- this->EnsureLoopBodyLoadSlot(symID);
- }
- if (m_func->DoStackNestedFunc() && symID == GetEnvReg())
- {
- // Environment is not guaranteed constant during this function because it could become boxed during execution,
- // so load the environment every time you need it.
- IR::RegOpnd *regOpnd = IR::RegOpnd::New(TyVar, m_func);
- this->AddInstr(
- IR::Instr::New(Js::OpCode::LdEnv, regOpnd, m_func),
- offset);
- sym = regOpnd->m_sym;
- }
- else
- {
- sym = StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func);
- }
- }
- return IR::RegOpnd::New(sym, TyVar, m_func);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlotI2<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- BuildElementSlotI2(newOpcode, offset, layout->Value, layout->SlotIndex1, layout->SlotIndex2, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledElementSlotI2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlotI2<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- BuildElementSlotI2(newOpcode, offset, layout->Value, layout->SlotIndex1, layout->SlotIndex2, layout->profileId);
- }
- void
- IRBuilder::BuildElementSlotI2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot,
- int32 slotId1, int32 slotId2, Js::ProfileId profileId)
- {
- IR::RegOpnd *regOpnd;
- IR::SymOpnd *fieldOpnd;
- IR::Instr *instr;
- PropertySym *fieldSym;
- bool isLdSlotThatWasNotProfiled = false;
- switch (newOpcode)
- {
- case Js::OpCode::LdModuleSlot:
- case Js::OpCode::StModuleSlot:
- {
- Field(Js::Var)* moduleExportVarArrayAddr = Js::JavascriptOperators::OP_GetModuleExportSlotArrayAddress(slotId1, slotId2, m_func->GetScriptContextInfo());
- IR::AddrOpnd* addrOpnd = IR::AddrOpnd::New(moduleExportVarArrayAddr, IR::AddrOpndKindConstantAddress, m_func, true);
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::Ld_A, regOpnd, addrOpnd, m_func);
- this->AddInstr(instr, offset);
- fieldSym = PropertySym::New(regOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- if (newOpcode == Js::OpCode::LdModuleSlot)
- {
- newOpcode = Js::OpCode::LdSlot;
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, regOpnd, fieldOpnd, m_func);
- }
- else
- {
- Assert(newOpcode == Js::OpCode::StModuleSlot);
- newOpcode = Js::OpCode::StSlot;
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
- }
- this->AddInstr(instr, offset);
- break;
- }
- case Js::OpCode::LdEnvSlot:
- case Js::OpCode::LdEnvObjSlot:
- case Js::OpCode::StEnvSlot:
- case Js::OpCode::StEnvSlotChkUndecl:
- case Js::OpCode::StEnvObjSlot:
- case Js::OpCode::StEnvObjSlotChkUndecl:
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), slotId1, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- switch (newOpcode)
- {
- case Js::OpCode::LdEnvObjSlot:
- case Js::OpCode::StEnvObjSlot:
- case Js::OpCode::StEnvObjSlotChkUndecl:
- m_func->GetTopFunc()->AddFrameDisplayCheck(fieldOpnd, (uint32)-1);
- fieldSym = PropertySym::New(regOpnd->m_sym, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var),
- (uint32)-1, (uint)-1, PropertyKindSlotArray, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- break;
- default:
- m_func->GetTopFunc()->AddFrameDisplayCheck(fieldOpnd, slotId2);
- break;
- }
- fieldSym = PropertySym::New(regOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- switch (newOpcode)
- {
- case Js::OpCode::LdEnvSlot:
- case Js::OpCode::LdEnvObjSlot:
- newOpcode = Js::OpCode::LdSlot;
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = nullptr;
- if (profileId != Js::Constants::NoProfileId)
- {
- instr = this->BuildProfiledSlotLoad(newOpcode, regOpnd, fieldOpnd, profileId, &isLdSlotThatWasNotProfiled);
- }
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, regOpnd, fieldOpnd, m_func);
- }
- break;
- default:
- newOpcode =
- newOpcode == Js::OpCode::StEnvSlot || newOpcode == Js::OpCode::StEnvObjSlot ? Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
- if (newOpcode == Js::OpCode::StSlotChkUndecl)
- {
- // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
- instr->SetSrc2(fieldOpnd);
- }
- break;
- }
- this->AddInstr(instr, offset);
- if(isLdSlotThatWasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- break;
- case Js::OpCode::StInnerObjSlot:
- case Js::OpCode::StInnerObjSlotChkUndecl:
- case Js::OpCode::StInnerSlot:
- case Js::OpCode::StInnerSlotChkUndecl:
- if ((uint)slotId1 >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- regOpnd = this->BuildSrcOpnd(regSlot);
- slotId1 += this->m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
- if ((uint)slotId1 >= this->m_func->GetJITFunctionBody()->GetLocalsCount())
- {
- Js::Throw::FatalInternalError();
- }
- if (newOpcode == Js::OpCode::StInnerObjSlot || newOpcode == Js::OpCode::StInnerObjSlotChkUndecl)
- {
- IR::RegOpnd * slotOpnd = IR::RegOpnd::New(TyVar, m_func);
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, slotId1, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, slotOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- PropertySym *propertySym = PropertySym::New(slotOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::PropertySymOpnd::New(propertySym, (Js::CacheId)-1, TyVar, m_func);
- }
- else
- {
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::StSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots);
- if (!this->DoSlotArrayCheck(fieldOpnd, IsLoopBody()))
- {
- // Need a dynamic check on the size of the local slot array.
- m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
- }
- }
- newOpcode =
- newOpcode == Js::OpCode::StInnerObjSlot || newOpcode == Js::OpCode::StInnerSlot ?
- Js::OpCode::StSlot : Js::OpCode::StSlotChkUndecl;
- instr = IR::Instr::New(newOpcode, fieldOpnd, regOpnd, m_func);
- if (newOpcode == Js::OpCode::StSlotChkUndecl)
- {
- // ChkUndecl includes an implicit read of the destination. Communicate the liveness by using the destination in src2.
- instr->SetSrc2(fieldOpnd);
- }
- this->AddInstr(instr, offset);
- break;
- case Js::OpCode::LdInnerSlot:
- case Js::OpCode::LdInnerObjSlot:
- if ((uint)slotId1 >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- slotId1 += this->m_func->GetJITFunctionBody()->GetFirstInnerScopeReg();
- if ((uint)slotId1 >= this->m_func->GetJITFunctionBody()->GetLocalsCount())
- {
- Js::Throw::FatalInternalError();
- }
- if (newOpcode == Js::OpCode::LdInnerObjSlot)
- {
- IR::RegOpnd * slotOpnd = IR::RegOpnd::New(TyVar, m_func);
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, slotId1, (Js::DynamicObject::GetOffsetOfAuxSlots())/sizeof(Js::Var), (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, slotOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- PropertySym *propertySym = PropertySym::New(slotOpnd->m_sym, slotId2, (uint32)-1, (uint)-1, PropertyKindSlots, m_func);
- fieldOpnd = IR::PropertySymOpnd::New(propertySym, (Js::CacheId)-1, TyVar, m_func);
- }
- else
- {
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlot, slotId1, slotId2, (Js::PropertyIdIndexType)-1, PropertyKindSlots);
- if (!this->DoSlotArrayCheck(fieldOpnd, IsLoopBody()))
- {
- // Need a dynamic check on the size of the local slot array.
- m_func->GetTopFunc()->AddSlotArrayCheck(fieldOpnd);
- }
- }
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(Js::OpCode::LdSlot, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- break;
- default:
- AssertMsg(false, "Unsupported opcode in BuildElementSlotI2");
- break;
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementSlotI3(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementSlotI3<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- this->DoClosureRegCheck(layout->HomeObj);
- }
- BuildElementSlotI3(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, layout->HomeObj, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledElementSlotI3(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementSlotI3<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- this->DoClosureRegCheck(layout->HomeObj);
- }
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- BuildElementSlotI3(newOpcode, offset, layout->Instance, layout->Value, layout->SlotIndex, layout->HomeObj, layout->profileId);
- }
- void
- IRBuilder::BuildElementSlotI3(Js::OpCode newOpcode, uint32 offset, Js::RegSlot fieldRegSlot, Js::RegSlot regSlot,
- int32 slotId, Js::RegSlot homeObj, Js::ProfileId profileId)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- IR::RegOpnd * regOpnd;
- switch (newOpcode)
- {
- case Js::OpCode::NewInnerScFuncHomeObj:
- newOpcode = Js::OpCode::NewScFuncHomeObj;
- goto NewScFuncCommon;
- case Js::OpCode::NewInnerScGenFuncHomeObj:
- newOpcode = Js::OpCode::NewScGenFuncHomeObj;
- NewScFuncCommon:
- {
- Js::FunctionInfoPtrPtr infoRef = m_func->GetJITFunctionBody()->GetNestedFuncRef(slotId);
- IR::AddrOpnd * functionBodySlotOpnd = IR::AddrOpnd::New((Js::Var)infoRef, IR::AddrOpndKindDynamicMisc, m_func);
- IR::Opnd * environmentOpnd = this->BuildSrcOpnd(fieldRegSlot);
- IR::Opnd * homeObjOpnd = this->BuildSrcOpnd(homeObj);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), homeObjOpnd, m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), functionBodySlotOpnd, instr->GetDst(), m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), environmentOpnd, instr->GetDst(), m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(newOpcode, regOpnd, instr->GetDst(), m_func);
- if (regOpnd->m_sym->m_isSingleDef)
- {
- regOpnd->m_sym->m_isSafeThis = true;
- regOpnd->m_sym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- return;
- }
- default:
- AssertMsg(UNREACHED, "Unknown ElementSlotI3 opcode");
- Fatal();
- }
- }
- IR::SymOpnd *
- IRBuilder::BuildLoopBodySlotOpnd(SymID symId)
- {
- Assert(!this->RegIsConstant((Js::RegSlot)symId));
- // Get the interpreter frame instance that was passed in.
- StackSym *loopParamSym = m_func->EnsureLoopParamSym();
- PropertySym * fieldSym = PropertySym::FindOrCreate(loopParamSym->m_id, (Js::PropertyId)(symId + this->m_loopBodyLocalsStartSlot), (uint32)-1, (uint)-1, PropertyKindLocalSlots, m_func);
- return IR::SymOpnd::New(fieldSym, TyVar, m_func);
- }
- void
- IRBuilder::EnsureLoopBodyLoadSlot(SymID symId, bool isCatchObjectSym)
- {
- // No need to emit LdSlot for a catch object. In fact, if we do, we might be loading an uninitialized value from the slot.
- if (isCatchObjectSym)
- {
- return;
- }
- StackSym * symDst = StackSym::FindOrCreate(symId, (Js::RegSlot)symId, m_func);
- if (symDst->m_isCatchObjectSym)
- {
- return;
- }
- AssertOrFailFast(symId < m_ldSlots->Length());
- if (this->m_ldSlots->TestAndSet(symId))
- {
- return;
- }
- IR::SymOpnd * fieldSymOpnd = this->BuildLoopBodySlotOpnd(symId);
- IR::RegOpnd * dstOpnd = IR::RegOpnd::New(symDst, TyVar, m_func);
- IR::Instr * ldSlotInstr;
- ValueType symValueType;
- if(m_func->GetWorkItem()->HasSymIdToValueTypeMap() && m_func->GetWorkItem()->TryGetValueType(symId, &symValueType))
- {
- ldSlotInstr = IR::ProfiledInstr::New(Js::OpCode::LdSlot, dstOpnd, fieldSymOpnd, m_func);
- ldSlotInstr->AsProfiledInstr()->u.FldInfo().valueType = symValueType;
- }
- else
- {
- ldSlotInstr = IR::Instr::New(Js::OpCode::LdSlot, dstOpnd, fieldSymOpnd, m_func);
- }
- m_func->m_headInstr->InsertAfter(ldSlotInstr);
- if (m_lastInstr == m_func->m_headInstr)
- {
- m_lastInstr = ldSlotInstr;
- }
- }
- void
- IRBuilder::SetLoopBodyStSlot(SymID symID, bool isCatchObjectSym)
- {
- if (this->m_func->HasTry() && !PHASE_OFF(Js::JITLoopBodyInTryCatchPhase, this->m_func))
- {
- // No need to emit StSlot for a catch object. In fact, if we do, we might be storing an uninitialized value to the slot.
- if (isCatchObjectSym)
- {
- return;
- }
- StackSym * dstSym = StackSym::FindOrCreate(symID, (Js::RegSlot)symID, m_func);
- Assert(dstSym);
- if (dstSym->m_isCatchObjectSym)
- {
- return;
- }
- }
- AssertOrFailFast(symID < m_stSlots->Length());
- this->m_stSlots->Set(symID);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementCP
- ///
- /// Build IR instr for an ElementCP or ElementRootCP instruction.
- ///
- ///----------------------------------------------------------------------------
- IR::Instr *
- IRBuilder::BuildProfiledFieldLoad(Js::OpCode loadOp, IR::RegOpnd *dstOpnd, IR::SymOpnd *srcOpnd, Js::CacheId inlineCacheIndex, bool *pUnprofiled)
- {
- IR::Instr * instr = nullptr;
- // Prefer JitProfilingInstr if we're in simplejit
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
- }
- else if (this->m_func->HasProfileInfo())
- {
- instr = IR::ProfiledInstr::New(loadOp, dstOpnd, srcOpnd, m_func);
- instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(inlineCacheIndex));
- *pUnprofiled = !instr->AsProfiledInstr()->u.FldInfo().WasLdFldProfiled();
- dstOpnd->SetValueType(instr->AsProfiledInstr()->u.FldInfo().valueType);
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if(Js::Configuration::Global.flags.TestTrace.IsEnabled(Js::DynamicProfilePhase))
- {
- const ValueType valueType(instr->AsProfiledInstr()->u.FldInfo().valueType);
- char valueTypeStr[VALUE_TYPE_MAX_STRING_SIZE];
- valueType.ToString(valueTypeStr);
- char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
- Output::Print(_u("TestTrace function %s (%s) ValueType = %i "), m_func->GetJITFunctionBody()->GetDisplayName(), m_func->GetDebugNumberSet(debugStringBuffer), valueTypeStr);
- instr->DumpTestTrace();
- }
- #endif
- }
- return instr;
- }
- Js::RegSlot IRBuilder::GetEnvRegForEvalCode() const
- {
- if (m_func->GetJITFunctionBody()->IsStrictMode() && m_func->GetJITFunctionBody()->IsGlobalFunc())
- {
- return m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg();
- }
- else
- {
- return GetEnvReg();
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementP(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementP<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- BuildElementP(newOpcode, offset, layout->Value, layout->inlineCacheIndex);
- }
- void
- IRBuilder::BuildElementP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- IR::RegOpnd * regOpnd;
- IR::Opnd * srcOpnd;
- IR::SymOpnd * fieldSymOpnd;
- Js::PropertyId propertyId;
- bool isProfiled = OpCodeAttr::IsProfiledOp(newOpcode);
- bool isLdFldThatWasNotProfiled = false;
- if (isProfiled)
- {
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- }
- propertyId = this->m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(inlineCacheIndex);
- Js::RegSlot instance = this->GetEnvRegForEvalCode();
- switch (newOpcode)
- {
- case Js::OpCode::LdLocalFld:
- if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- newOpcode = Js::OpCode::LdFld;
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
- if (fieldSymOpnd->IsPropertySymOpnd())
- {
- fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
- }
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = nullptr;
- if (isProfiled)
- {
- instr = this->BuildProfiledFieldLoad(newOpcode, regOpnd, fieldSymOpnd, inlineCacheIndex, &isLdFldThatWasNotProfiled);
- }
- // If it hasn't been set yet
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- }
- break;
- case Js::OpCode::StLocalFld:
- if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
- if (fieldSymOpnd->IsPropertySymOpnd())
- {
- fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
- }
- srcOpnd = this->BuildSrcOpnd(regSlot);
- newOpcode = Js::OpCode::StFld;
- goto stCommon;
- case Js::OpCode::InitLocalFld:
- case Js::OpCode::InitLocalLetFld:
- case Js::OpCode::InitUndeclLocalLetFld:
- case Js::OpCode::InitUndeclLocalConstFld:
- {
- if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
- // Store
- if (newOpcode == Js::OpCode::InitUndeclLocalLetFld)
- {
- srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
- srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
- newOpcode = Js::OpCode::InitLetFld;
- }
- else if (newOpcode == Js::OpCode::InitUndeclLocalConstFld)
- {
- srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
- srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
- newOpcode = Js::OpCode::InitConstFld;
- }
- else
- {
- srcOpnd = this->BuildSrcOpnd(regSlot);
- newOpcode = newOpcode == Js::OpCode::InitLocalFld ? Js::OpCode::InitFld : Js::OpCode::InitLetFld;
- }
- stCommon:
- instr = nullptr;
- if (isProfiled)
- {
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
- }
- else if (this->m_func->HasProfileInfo())
- {
- instr = IR::ProfiledInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
- instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(inlineCacheIndex));
- }
- }
- // If it hasn't been set yet
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
- }
- break;
- }
- case Js::OpCode::ScopedLdFld:
- case Js::OpCode::ScopedLdFldForTypeOf:
- {
- Assert(!isProfiled);
- Assert(this->m_func->GetScriptContextInfo()->GetAddr() == this->m_func->GetTopFunc()->GetScriptContextInfo()->GetAddr());
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- break;
- }
- case Js::OpCode::ScopedStFld:
- case Js::OpCode::ConsoleScopedStFld:
- case Js::OpCode::ScopedStFldStrict:
- case Js::OpCode::ConsoleScopedStFldStrict:
- {
- Assert(!isProfiled);
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
- // Implicit root object as default instance
- IR::Opnd * instance2Opnd = this->BuildSrcOpnd(Js::FunctionBody::RootObjectRegSlot);
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, instance2Opnd, m_func);
- break;
- }
- default:
- AssertMsg(UNREACHED, "Unknown ElementP opcode");
- Fatal();
- }
- this->AddInstr(instr, offset);
- if(isLdFldThatWasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementPIndexed(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementPIndexed<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- switch (newOpcode)
- {
- case Js::OpCode::InitInnerFld:
- newOpcode = Js::OpCode::InitFld;
- goto initinnerfldcommon;
- case Js::OpCode::InitInnerLetFld:
- newOpcode = Js::OpCode::InitLetFld;
- // fall through
- initinnerfldcommon:
- case Js::OpCode::InitUndeclLetFld:
- case Js::OpCode::InitUndeclConstFld:
- BuildElementCP(newOpcode, offset, InnerScopeIndexToRegSlot(layout->scopeIndex), layout->Value, layout->inlineCacheIndex);
- break;
- default:
- AssertMsg(false, "Unknown opcode for ElementPIndexed");
- break;
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementCP(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementCP<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildElementCP(newOpcode, offset, layout->Instance, layout->Value, layout->inlineCacheIndex);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementRootCP(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementRootCP<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- }
- BuildElementCP(newOpcode, offset, Js::FunctionBody::RootObjectRegSlot, layout->Value, layout->inlineCacheIndex);
- }
- void
- IRBuilder::BuildElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- Js::PropertyId propertyId;
- bool isProfiled = OpCodeAttr::IsProfiledOp(newOpcode);
- if (isProfiled)
- {
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- }
- propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(inlineCacheIndex);
- IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType)-1, PropertyKindData, inlineCacheIndex);
- IR::RegOpnd * regOpnd;
- IR::Instr * instr = nullptr;
- bool isLdFldThatWasNotProfiled = false;
- switch (newOpcode)
- {
- case Js::OpCode::LdFldForTypeOf:
- case Js::OpCode::LdFld:
- case Js::OpCode::LdLen_A:
- if (fieldSymOpnd->IsPropertySymOpnd())
- {
- fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
- }
- case Js::OpCode::LdFldForCallApplyTarget:
- case Js::OpCode::LdRootFldForTypeOf:
- case Js::OpCode::LdRootFld:
- case Js::OpCode::LdMethodFld:
- case Js::OpCode::LdRootMethodFld:
- case Js::OpCode::ScopedLdMethodFld:
- // Load
- // LdMethodFromFlags is backend only. Don't need to be added here.
- regOpnd = this->BuildDstOpnd(regSlot);
- if (isProfiled)
- {
- instr = this->BuildProfiledFieldLoad(newOpcode, regOpnd, fieldSymOpnd, inlineCacheIndex, &isLdFldThatWasNotProfiled);
- }
- // If it hasn't been set yet
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- }
- if (newOpcode == Js::OpCode::LdFld ||
- newOpcode == Js::OpCode::LdFldForCallApplyTarget ||
- newOpcode == Js::OpCode::LdMethodFld ||
- newOpcode == Js::OpCode::LdRootMethodFld ||
- newOpcode == Js::OpCode::ScopedLdMethodFld)
- {
- // Check whether we're loading (what appears to be) a built-in method.
- Js::BuiltinFunction builtInIndex = Js::BuiltinFunction::None;
- PropertySym *fieldSym = fieldSymOpnd->m_sym->AsPropertySym();
- this->CheckBuiltIn(fieldSym, &builtInIndex);
- regOpnd->m_sym->m_builtInIndex = builtInIndex;
- }
- break;
- case Js::OpCode::StFld:
- if (fieldSymOpnd->IsPropertySymOpnd())
- {
- fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
- }
- case Js::OpCode::InitFld:
- case Js::OpCode::InitRootFld:
- case Js::OpCode::InitLetFld:
- case Js::OpCode::InitRootLetFld:
- case Js::OpCode::InitConstFld:
- case Js::OpCode::InitRootConstFld:
- case Js::OpCode::InitUndeclLetFld:
- case Js::OpCode::InitUndeclConstFld:
- case Js::OpCode::InitClassMember:
- case Js::OpCode::StRootFld:
- case Js::OpCode::StFldStrict:
- case Js::OpCode::StRootFldStrict:
- {
- IR::Opnd *srcOpnd;
- // Store
- if (newOpcode == Js::OpCode::InitUndeclLetFld)
- {
- srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
- srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
- newOpcode = Js::OpCode::InitLetFld;
- }
- else if (newOpcode == Js::OpCode::InitUndeclConstFld)
- {
- srcOpnd = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(), IR::AddrOpndKindDynamicVar, this->m_func, true);
- srcOpnd->SetValueType(ValueType::PrimitiveOrObject);
- newOpcode = Js::OpCode::InitConstFld;
- }
- else
- {
- srcOpnd = this->BuildSrcOpnd(regSlot);
- }
- if (isProfiled)
- {
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
- }
- else if (this->m_func->HasProfileInfo())
- {
- instr = IR::ProfiledInstr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
- instr->AsProfiledInstr()->u.FldInfo() = *(m_func->GetReadOnlyProfileInfo()->GetFldInfo(inlineCacheIndex));
- }
- }
- // If it hasn't been set yet
- if (!instr)
- {
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, srcOpnd, m_func);
- }
- break;
- }
- default:
- AssertMsg(UNREACHED, "Unknown ElementCP opcode");
- Fatal();
- }
- this->AddInstr(instr, offset);
- if(isLdFldThatWasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledElementCP(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementCP<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildProfiledElementCP(newOpcode, offset, layout->Instance, layout->Value, layout->inlineCacheIndex, layout->profileId);
- }
- void
- IRBuilder::BuildProfiledElementCP(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::RegSlot regSlot, Js::CacheId inlineCacheIndex, Js::ProfileId profileId)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- Assert(newOpcode == Js::OpCode::LdLen_A);
- Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(inlineCacheIndex);
- IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, (Js::PropertyIdIndexType) - 1, PropertyKindData, inlineCacheIndex);
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(regSlot);
- bool isProfiled = (profileId != Js::Constants::NoProfileId);
- ValueType arrayType = ValueType::Uninitialized;
- const Js::LdLenInfo * ldLenInfo = nullptr;
- if (m_func->HasProfileInfo())
- {
- ldLenInfo = m_func->GetReadOnlyProfileInfo()->GetLdLenInfo(profileId);
- arrayType = (ldLenInfo->GetArrayType());
- if (arrayType.IsLikelyNativeArray() && !AllowNativeArrayProfileInfo())
- {
- // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the ProfiledInstr.
- arrayType = arrayType.SetArrayTypeId(Js::TypeIds_Array);
- }
- fieldSymOpnd->SetValueType(arrayType);
- if (m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry())
- {
- isProfiled = false;
- }
- }
- else
- {
- isProfiled = false;
- }
- bool wasNotProfiled = false;
- IR::Instr *instr = nullptr;
- if (isProfiled)
- {
- instr = this->BuildProfiledFieldLoad(newOpcode, dstOpnd, fieldSymOpnd, inlineCacheIndex, &wasNotProfiled);
- }
- if (instr == nullptr)
- {
- instr = IR::Instr::New(newOpcode, dstOpnd, fieldSymOpnd, m_func);
- }
- else if (instr->IsJitProfilingInstr())
- {
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else if (instr->IsProfiledInstr())
- {
- instr->AsProfiledInstr()->u.LdLenInfo() = *ldLenInfo;
- instr->AsProfiledInstr()->u.LdLenInfo().arrayType = arrayType;
- }
- this->AddInstr(instr, offset);
- if (wasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementC2
- ///
- /// Build IR instr for an ElementC2 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementScopedC2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementScopedC2<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Value2);
- }
- BuildElementScopedC2(newOpcode, offset, layout->Value2, layout->Value, layout->PropertyIdIndex);
- }
- void
- IRBuilder::BuildElementScopedC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot value2Slot,
- Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
- {
- IR::Instr * instr = nullptr;
- Js::PropertyId propertyId;
- IR::RegOpnd * regOpnd;
- IR::RegOpnd * value2Opnd;
- IR::SymOpnd * fieldSymOpnd;
- Js::RegSlot instanceSlot = this->GetEnvRegForEvalCode();
- switch (newOpcode)
- {
- case Js::OpCode::ScopedLdInst:
- {
- propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instanceSlot, propertyId, propertyIdIndex, PropertyKindData);
- regOpnd = this->BuildDstOpnd(regSlot);
- value2Opnd = this->BuildDstOpnd(value2Slot);
- IR::Instr *newInstr = IR::Instr::New(Js::OpCode::Unused, value2Opnd, m_func);
- this->AddInstr(newInstr, offset);
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, newInstr->GetDst(), m_func);
- this->AddInstr(instr, offset);
- }
- break;
- default:
- AssertMsg(UNREACHED, "Unknown ElementC2 opcode");
- Fatal();
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementC2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementC2<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Value2);
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildElementC2(newOpcode, offset, layout->Instance, layout->Value2, layout->Value, layout->PropertyIdIndex);
- }
- void
- IRBuilder::BuildElementC2(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instanceSlot, Js::RegSlot value2Slot,
- Js::RegSlot regSlot, Js::PropertyIdIndexType propertyIdIndex)
- {
- IR::Instr * instr = nullptr;
- Js::PropertyId propertyId;
- IR::RegOpnd * regOpnd;
- IR::RegOpnd * value2Opnd;
- IR::SymOpnd * fieldSymOpnd;
- switch (newOpcode)
- {
- case Js::OpCode::ProfiledLdSuperFld:
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- // fall-through
- case Js::OpCode::LdSuperFld:
- {
- propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(propertyIdIndex);
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instanceSlot, propertyId, (Js::PropertyIdIndexType) - 1, PropertyKindData, propertyIdIndex);
- if (fieldSymOpnd->IsPropertySymOpnd())
- {
- fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
- }
- value2Opnd = this->BuildSrcOpnd(value2Slot);
- regOpnd = this->BuildDstOpnd(regSlot);
- instr = IR::ProfiledInstr::New(newOpcode, regOpnd, fieldSymOpnd, value2Opnd, m_func);
- this->AddInstr(instr, offset);
- }
- break;
- case Js::OpCode::ProfiledStSuperFld:
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- // fall-through
- case Js::OpCode::StSuperFld:
- {
- propertyId = m_func->GetJITFunctionBody()->GetPropertyIdFromCacheId(propertyIdIndex);
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instanceSlot, propertyId, (Js::PropertyIdIndexType) - 1, PropertyKindData, propertyIdIndex);
- if (fieldSymOpnd->IsPropertySymOpnd())
- {
- fieldSymOpnd->AsPropertySymOpnd()->TryDisableRuntimePolymorphicCache();
- }
- regOpnd = this->BuildSrcOpnd(regSlot);
- value2Opnd = this->BuildSrcOpnd(value2Slot);
- instr = IR::ProfiledInstr::New(newOpcode, fieldSymOpnd, regOpnd, value2Opnd, m_func);
- this->AddInstr(instr, offset);
- break;
- }
- default:
- AssertMsg(UNREACHED, "Unknown ElementC2 opcode");
- Fatal();
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementU
- ///
- /// Build IR instr for an ElementU or ElementRootU instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementU(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementU<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildElementU(newOpcode, offset, layout->Instance, layout->PropertyIdIndex);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementRootU(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementRootU<SizePolicy>>();
- BuildElementU(newOpcode, offset, Js::FunctionBody::RootObjectRegSlot, layout->PropertyIdIndex);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementScopedU(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementScopedU<SizePolicy>>();
- BuildElementU(newOpcode, offset, GetEnvReg(), layout->PropertyIdIndex);
- }
- void
- IRBuilder::BuildElementU(Js::OpCode newOpcode, uint32 offset, Js::RegSlot instance, Js::PropertyIdIndexType propertyIdIndex)
- {
- IR::Instr * instr;
- IR::RegOpnd * regOpnd;
- IR::SymOpnd * fieldSymOpnd;
- Js::PropertyId propertyId = m_func->GetJITFunctionBody()->GetReferencedPropertyId(propertyIdIndex);
- switch (newOpcode)
- {
- case Js::OpCode::LdLocalElemUndef:
- if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- instance = m_func->GetJITFunctionBody()->GetLocalClosureReg();
- newOpcode = Js::OpCode::LdElemUndef;
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, propertyIdIndex, PropertyKindData);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, m_func);
- break;
- // fall through
- case Js::OpCode::LdElemUndefScoped:
- {
- // Store
- PropertyKind propertyKind = PropertyKindData;
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, propertyIdIndex, propertyKind);
- // Implicit root object as default instance
- regOpnd = this->BuildSrcOpnd(Js::FunctionBody::RootObjectRegSlot);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
- break;
- }
- case Js::OpCode::ClearAttributes:
- {
- instr = IR::Instr::New(newOpcode, m_func);
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(instance);
- IR::IntConstOpnd * src2Opnd = IR::IntConstOpnd::New(propertyId, TyInt32, m_func);
- instr->SetSrc1(src1Opnd);
- instr->SetSrc2(src2Opnd);
- break;
- }
- case Js::OpCode::StLocalFuncExpr:
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, propertyIdIndex, PropertyKindData);
- regOpnd = this->BuildSrcOpnd(instance);
- newOpcode = Js::OpCode::StFuncExpr;
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, regOpnd, m_func);
- break;
- case Js::OpCode::DeleteLocalFld:
- newOpcode = Js::OpCode::DeleteFld;
- fieldSymOpnd = BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, propertyIdIndex, PropertyKindData);
- regOpnd = BuildDstOpnd(instance);
- instr = IR::Instr::New(newOpcode, regOpnd, fieldSymOpnd, m_func);
- break;
- default:
- {
- fieldSymOpnd = this->BuildFieldOpnd(newOpcode, instance, propertyId, propertyIdIndex, PropertyKindData);
- instr = IR::Instr::New(newOpcode, fieldSymOpnd, m_func);
- break;
- }
- }
- this->AddInstr(instr, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildAuxiliary
- ///
- /// Build IR instr for an Auxiliary instruction.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::BuildAuxNoReg(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- const unaligned Js::OpLayoutAuxNoReg *auxInsn = m_jnReader.AuxNoReg();
- switch (newOpcode)
- {
- case Js::OpCode::InitCachedFuncs:
- {
- IR::Opnd *src1Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
- IR::Opnd *src2Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg());
- IR::Opnd *src3Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxFuncInfoArray, auxInsn->Offset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- IR::HelperCallOpnd *helperOpnd;
- helperOpnd = IR::HelperCallOpnd::New(IR::HelperOP_InitCachedFuncs, this->m_func);
- src2Opnd = instr->GetDst();
- instr = IR::Instr::New(Js::OpCode::CallHelper, m_func);
- instr->SetSrc1(helperOpnd);
- instr->SetSrc2(src2Opnd);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- return;
- }
- default:
- {
- AssertMsg(UNREACHED, "Unknown AuxNoReg opcode");
- Fatal();
- break;
- }
- }
- }
- void
- IRBuilder::BuildAuxiliary(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- const unaligned Js::OpLayoutAuxiliary *auxInsn = m_jnReader.Auxiliary();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(auxInsn->R0);
- }
- IR::Instr *instr;
- switch (newOpcode)
- {
- case Js::OpCode::NewScObjectLiteral:
- {
- int literalObjectId = auxInsn->C1;
- IR::RegOpnd * dstOpnd;
- IR::Opnd* srcOpnd;
- Js::RegSlot dstRegSlot = auxInsn->R0;
- // The property ID array needs to be both relocatable and available (so we can
- // get the slot capacity), so we need to just pass the offset to lower and let
- // lower take it from there...
- srcOpnd = IR::IntConstOpnd::New(auxInsn->Offset, TyUint32, m_func);
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
- instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- // Because we're going to be making decisions based off the value, we have to defer
- // this until we get to lowering.
- instr->SetSrc2(IR::IntConstOpnd::New(literalObjectId, TyUint32, m_func));
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isSafeThis = true;
- }
- break;
- }
- case Js::OpCode::LdPropIds:
- {
- IR::RegOpnd * dstOpnd;
- IR::Opnd* srcOpnd;
- Js::RegSlot dstRegSlot = auxInsn->R0;
- srcOpnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxPropertyIdArray, auxInsn->Offset);
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- break;
- }
- case Js::OpCode::NewScIntArray:
- {
- IR::RegOpnd* dstOpnd;
- IR::Opnd* src1Opnd;
- src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, auxInsn->Offset);
- dstOpnd = this->BuildDstOpnd(auxInsn->R0);
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- const Js::TypeId arrayTypeId = m_func->IsJitInDebugMode() ? Js::TypeIds_Array : Js::TypeIds_NativeIntArray;
- dstOpnd->SetValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
- dstOpnd->SetValueTypeFixed();
- break;
- }
- case Js::OpCode::NewScFltArray:
- {
- IR::RegOpnd* dstOpnd;
- IR::Opnd* src1Opnd;
- src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxFloatArray, auxInsn->Offset);
- dstOpnd = this->BuildDstOpnd(auxInsn->R0);
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- const Js::TypeId arrayTypeId = m_func->IsJitInDebugMode() ? Js::TypeIds_Array : Js::TypeIds_NativeFloatArray;
- dstOpnd->SetValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
- dstOpnd->SetValueTypeFixed();
- break;
- }
- case Js::OpCode::StArrSegItem_A:
- {
- IR::RegOpnd* src1Opnd;
- IR::Opnd* src2Opnd;
- src1Opnd = this->BuildSrcOpnd(auxInsn->R0);
- src2Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxVarsArray, auxInsn->Offset);
- instr = IR::Instr::New(newOpcode, m_func);
- instr->SetSrc1(src1Opnd);
- instr->SetSrc2(src2Opnd);
- break;
- }
- case Js::OpCode::NewScObject_A:
- {
- const Js::VarArrayVarCount *vars = (Js::VarArrayVarCount *)m_func->GetJITFunctionBody()->ReadFromAuxContextData(auxInsn->Offset);
- int count = Js::TaggedInt::ToInt32(vars->count);
- StackSym * symDst;
- IR::SymOpnd * dstOpnd;
- IR::Opnd * src1Opnd;
- //
- // PUSH all the parameters on the auxiliary context, to the stack
- //
- for (int i=0;i<count; i++)
- {
- m_argsOnStack++;
- symDst = m_func->m_symTable->GetArgSlotSym((uint16)(i + 2));
- if (symDst == nullptr || (uint16)(i + 2) != (i + 2))
- {
- AssertMsg(UNREACHED, "Arg count too big...");
- Fatal();
- }
- dstOpnd = IR::SymOpnd::New(symDst, TyVar, m_func);
- src1Opnd = IR::AddrOpnd::New(vars->elements[i], IR::AddrOpndKindDynamicVar, this->m_func, true);
- instr = IR::Instr::New(Js::OpCode::ArgOut_A, dstOpnd, src1Opnd, m_func);
- this->AddInstr(instr, offset);
- m_argStack->Push(instr);
- }
- BuildCallI_Helper(Js::OpCode::NewScObject, offset, (Js::RegSlot)auxInsn->R0, (Js::RegSlot)auxInsn->C1, (Js::ArgSlot)count+1, Js::Constants::NoProfileId);
- return;
- }
- default:
- {
- AssertMsg(UNREACHED, "Unknown Auxiliary opcode");
- Fatal();
- break;
- }
- }
- this->AddInstr(instr, offset);
- }
- void
- IRBuilder::BuildProfiledAuxiliary(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- const unaligned Js::OpLayoutDynamicProfile<Js::OpLayoutAuxiliary> *auxInsn = m_jnReader.ProfiledAuxiliary();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(auxInsn->R0);
- }
- switch (newOpcode)
- {
- case Js::OpCode::ProfiledNewScIntArray:
- {
- Js::ProfileId profileId = static_cast<Js::ProfileId>(auxInsn->profileId);
- IR::RegOpnd* dstOpnd;
- IR::Opnd* src1Opnd;
- src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, auxInsn->Offset);
- dstOpnd = this->BuildDstOpnd(auxInsn->R0);
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- IR::Instr *instr;
- Js::ArrayCallSiteInfo *arrayInfo = nullptr;
- Js::TypeId arrayTypeId = Js::TypeIds_Array;
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else if (m_func->HasArrayInfo())
- {
- instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr->AsProfiledInstr()->u.profileId = profileId;
- arrayInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId);
- if (arrayInfo && !m_func->IsJitInDebugMode())
- {
- if (arrayInfo->IsNativeIntArray())
- {
- arrayTypeId = Js::TypeIds_NativeIntArray;
- }
- else if (arrayInfo->IsNativeFloatArray())
- {
- arrayTypeId = Js::TypeIds_NativeFloatArray;
- }
- }
- }
- else
- {
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- }
- ValueType dstValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
- if (dstValueType.IsLikelyNativeArray())
- {
- dstOpnd->SetValueType(dstValueType.ToLikely());
- }
- else
- {
- dstOpnd->SetValueType(dstValueType);
- dstOpnd->SetValueTypeFixed();
- }
- StackSym *dstSym = dstOpnd->AsRegOpnd()->m_sym;
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isSafeThis = true;
- dstSym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- break;
- }
- case Js::OpCode::ProfiledNewScFltArray:
- {
- Js::ProfileId profileId = static_cast<Js::ProfileId>(auxInsn->profileId);
- IR::RegOpnd* dstOpnd;
- IR::Opnd* src1Opnd;
- src1Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxFloatArray, auxInsn->Offset);
- dstOpnd = this->BuildDstOpnd(auxInsn->R0);
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- IR::Instr *instr;
- Js::ArrayCallSiteInfo *arrayInfo = nullptr;
- if (m_func->DoSimpleJitDynamicProfile())
- {
- instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- // Keep arrayInfo null because we aren't using profile data in profiling simplejit
- }
- else
- {
- instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr->AsProfiledInstr()->u.profileId = profileId;
- if (m_func->HasArrayInfo()) {
- arrayInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId);
- }
- }
- Js::TypeId arrayTypeId;
- if (arrayInfo && arrayInfo->IsNativeFloatArray())
- {
- arrayTypeId = Js::TypeIds_NativeFloatArray;
- }
- else
- {
- arrayTypeId = Js::TypeIds_Array;
- }
- ValueType dstValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
- if (dstValueType.IsLikelyNativeArray())
- {
- dstOpnd->SetValueType(dstValueType.ToLikely());
- }
- else
- {
- dstOpnd->SetValueType(dstValueType);
- dstOpnd->SetValueTypeFixed();
- }
- StackSym *dstSym = dstOpnd->AsRegOpnd()->m_sym;
- if (dstSym->m_isSingleDef)
- {
- dstSym->m_isSafeThis = true;
- dstSym->m_isNotNumber = true;
- }
- this->AddInstr(instr, offset);
- break;
- }
- default:
- {
- AssertMsg(UNREACHED, "Unknown Auxiliary opcode");
- Fatal();
- break;
- }
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildReg2Aux
- ///
- /// Build IR instr for a Reg2Aux instruction.
- ///
- ///----------------------------------------------------------------------------
- void IRBuilder::BuildInitCachedScope(int auxOffset, int offset)
- {
- IR::Instr * instr;
- IR::RegOpnd * dstOpnd;
- IR::RegOpnd * src1Opnd;
- IR::AddrOpnd * src2Opnd;
- IR::Opnd* src3Opnd;
- IR::Opnd* formalsAreLetDeclOpnd;
- src2Opnd = IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetFormalsPropIdArrayAddr(), IR::AddrOpndKindDynamicMisc, m_func);
- Js::PropertyIdArray * propIds = m_func->GetJITFunctionBody()->GetFormalsPropIdArray();
- src3Opnd = this->BuildAuxObjectLiteralTypeRefOpnd(Js::ActivationObjectEx::GetLiteralObjectRef(propIds));
- dstOpnd = this->BuildDstOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
- formalsAreLetDeclOpnd = IR::IntConstOpnd::New(propIds->hasNonSimpleParams, TyUint8, m_func);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), formalsAreLetDeclOpnd, m_func);
- this->AddInstr(instr, offset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src3Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src2Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- // Disable opt that normally gets disabled when we see LdFuncExpr in the byte code.
- m_func->DisableCanDoInlineArgOpt();
- src1Opnd = IR::RegOpnd::New(TyVar, m_func);
- IR::Instr * instrLdFuncExpr = IR::Instr::New(Js::OpCode::LdFuncExpr, src1Opnd, m_func);
- this->AddInstr(instrLdFuncExpr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::ExtendArg_A, IR::RegOpnd::New(TyVar, m_func), src1Opnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- instr = IR::Instr::New(Js::OpCode::InitCachedScope, dstOpnd, instr->GetDst(), m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- }
- void
- IRBuilder::BuildReg2Aux(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- const unaligned Js::OpLayoutReg2Aux *auxInsn = m_jnReader.Reg2Aux();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(auxInsn->R0);
- this->DoClosureRegCheck(auxInsn->R1);
- }
- IR::Instr *instr;
- switch (newOpcode)
- {
- case Js::OpCode::SpreadArrayLiteral:
- {
- IR::RegOpnd * dstOpnd;
- IR::RegOpnd * src1Opnd;
- IR::Opnd* src2Opnd;
- Js::RegSlot dstRegSlot = auxInsn->R0;
- Js::RegSlot srcRegSlot = auxInsn->R1;
- src1Opnd = this->BuildSrcOpnd(srcRegSlot);
- src2Opnd = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, auxInsn->Offset);
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- instr = IR::Instr::New(Js::OpCode::SpreadArrayLiteral, dstOpnd, src1Opnd, src2Opnd, m_func);
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- if (dstOpnd->m_sym->m_isSingleDef)
- {
- dstOpnd->m_sym->m_isNotNumber = true;
- }
- break;
- }
- default:
- {
- AssertMsg(UNREACHED, "Unknown Reg2Aux opcode");
- Fatal();
- break;
- }
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementI
- ///
- /// Build IR instr for an ElementI instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementI(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementI<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- this->DoClosureRegCheck(layout->Element);
- }
- BuildElementI(newOpcode, offset, layout->Instance, layout->Element, layout->Value, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledElementI(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_ElementI<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- this->DoClosureRegCheck(layout->Element);
- }
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- BuildElementI(newOpcode, offset, layout->Instance, layout->Element, layout->Value, layout->profileId);
- }
- void
- IRBuilder::BuildElementI(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, Js::RegSlot indexRegSlot,
- Js::RegSlot regSlot, Js::ProfileId profileId)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- ValueType arrayType;
- const Js::LdElemInfo *ldElemInfo = nullptr;
- const Js::StElemInfo *stElemInfo = nullptr;
- bool isProfiledLoad = false;
- bool isProfiledStore = false;
- bool isProfiledInstr = (profileId != Js::Constants::NoProfileId);
- bool isLdElemOrStElemThatWasNotProfiled = false;
- if (isProfiledInstr)
- {
- switch (newOpcode)
- {
- case Js::OpCode::LdElemI_A:
- if (!DoLoadInstructionArrayProfileInfo())
- {
- break;
- }
- ldElemInfo = this->m_func->GetReadOnlyProfileInfo()->GetLdElemInfo(profileId);
- arrayType = ldElemInfo->GetArrayType();
- isLdElemOrStElemThatWasNotProfiled = !ldElemInfo->WasProfiled();
- isProfiledLoad = true;
- break;
- case Js::OpCode::StElemI_A:
- case Js::OpCode::StElemI_A_Strict:
- if (!DoLoadInstructionArrayProfileInfo())
- {
- break;
- }
- isProfiledStore = true;
- stElemInfo = this->m_func->GetReadOnlyProfileInfo()->GetStElemInfo(profileId);
- arrayType = stElemInfo->GetArrayType();
- isLdElemOrStElemThatWasNotProfiled = !stElemInfo->WasProfiled();
- break;
- }
- }
- IR::Instr * instr;
- IR::RegOpnd * regOpnd;
- IR::IndirOpnd * indirOpnd;
- indirOpnd = this->BuildIndirOpnd(this->BuildSrcOpnd(baseRegSlot), this->BuildSrcOpnd(indexRegSlot));
- if (isProfiledLoad || isProfiledStore)
- {
- if(arrayType.IsLikelyNativeArray() && !AllowNativeArrayProfileInfo())
- {
- arrayType = arrayType.SetArrayTypeId(Js::TypeIds_Array);
- // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the
- // ProfiledInstr.
- if(isProfiledLoad)
- {
- Js::LdElemInfo *const newLdElemInfo = JitAnew(m_func->m_alloc, Js::LdElemInfo, *ldElemInfo);
- newLdElemInfo->arrayType = arrayType;
- ldElemInfo = newLdElemInfo;
- }
- else
- {
- Js::StElemInfo *const newStElemInfo = JitAnew(m_func->m_alloc, Js::StElemInfo, *stElemInfo);
- newStElemInfo->arrayType = arrayType;
- stElemInfo = newStElemInfo;
- }
- }
- indirOpnd->GetBaseOpnd()->SetValueType(arrayType);
- if (m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry())
- {
- isProfiledLoad = false;
- isProfiledStore = false;
- }
- }
- switch (newOpcode)
- {
- case Js::OpCode::LdMethodElem:
- case Js::OpCode::LdElemI_A:
- case Js::OpCode::DeleteElemI_A:
- case Js::OpCode::DeleteElemIStrict_A:
- case Js::OpCode::TypeofElem:
- {
- // Evaluate to register
- regOpnd = this->BuildDstOpnd(regSlot);
- if (m_func->DoSimpleJitDynamicProfile() && isProfiledInstr)
- {
- instr = IR::JitProfilingInstr::New(newOpcode, regOpnd, indirOpnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else if (isProfiledLoad)
- {
- instr = IR::ProfiledInstr::New(newOpcode, regOpnd, indirOpnd, m_func);
- instr->AsProfiledInstr()->u.ldElemInfo = ldElemInfo;
- }
- else
- {
- instr = IR::Instr::New(newOpcode, regOpnd, indirOpnd, m_func);
- }
- break;
- }
- case Js::OpCode::StElemI_A:
- case Js::OpCode::StElemI_A_Strict:
- {
- // Store
- regOpnd = this->BuildSrcOpnd(regSlot);
- if (m_func->DoSimpleJitDynamicProfile() && isProfiledInstr)
- {
- instr = IR::JitProfilingInstr::New(newOpcode, indirOpnd, regOpnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- }
- else if (isProfiledStore)
- {
- instr = IR::ProfiledInstr::New(newOpcode, indirOpnd, regOpnd, m_func);
- instr->AsProfiledInstr()->u.stElemInfo = stElemInfo;
- }
- else
- {
- instr = IR::Instr::New(newOpcode, indirOpnd, regOpnd, m_func);
- }
- break;
- }
- case Js::OpCode::InitSetElemI:
- case Js::OpCode::InitGetElemI:
- case Js::OpCode::InitComputedProperty:
- case Js::OpCode::InitClassMemberComputedName:
- case Js::OpCode::InitClassMemberGetComputedName:
- case Js::OpCode::InitClassMemberSetComputedName:
- {
- regOpnd = this->BuildSrcOpnd(regSlot);
- instr = IR::Instr::New(newOpcode, indirOpnd, regOpnd, m_func);
- break;
- }
- default:
- AssertMsg(false, "Unknown ElementI opcode");
- return;
- }
- this->AddInstr(instr, offset);
- if(isLdElemOrStElemThatWasNotProfiled && DoBailOnNoProfile())
- {
- InsertBailOnNoProfile(instr);
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildElementUnsigned1
- ///
- /// Build IR instr for an ElementUnsigned1 instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildElementUnsigned1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ElementUnsigned1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Value);
- this->DoClosureRegCheck(layout->Instance);
- }
- BuildElementUnsigned1(newOpcode, offset, layout->Instance, layout->Element, layout->Value);
- }
- void
- IRBuilder::BuildElementUnsigned1(Js::OpCode newOpcode, uint32 offset, Js::RegSlot baseRegSlot, uint32 index, Js::RegSlot regSlot)
- {
- // This is an array-style access with a constant (integer) index.
- // Embed the index in the indir opnd as a constant offset.
- IR::Instr * instr;
- const bool simpleJit = m_func->DoSimpleJitDynamicProfile();
- IR::RegOpnd * regOpnd;
- IR::IndirOpnd * indirOpnd;
- IR::RegOpnd * baseOpnd;
- Js::OpCode opcode;
- switch (newOpcode)
- {
- case Js::OpCode::StArrItemI_CI4:
- {
- baseOpnd = this->BuildSrcOpnd(baseRegSlot);
- // This instruction must not create missing values in the array
- baseOpnd->SetValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(false).SetArrayTypeId(Js::TypeIds_Array));
- baseOpnd->SetValueTypeFixed();
- // In the case of simplejit, we won't know the exact type of array used until run time. Due to this,
- // we must use the specialized version of StElemC in Lowering.
- opcode = simpleJit ? Js::OpCode::StElemC : Js::OpCode::StElemI_A;
- break;
- }
- case Js::OpCode::StArrItemC_CI4:
- {
- baseOpnd = IR::RegOpnd::New(TyVar, m_func);
- // Insert LdArrHead as the next instr and clear the offset to avoid duplication.
- IR::RegOpnd *const arrayOpnd = this->BuildSrcOpnd(baseRegSlot);
- // This instruction must not create missing values in the array
- arrayOpnd->SetValueType(
- ValueType::GetObject(ObjectType::Array).SetHasNoMissingValues(false).SetArrayTypeId(Js::TypeIds_Array));
- arrayOpnd->SetValueTypeFixed();
- this->AddInstr(IR::Instr::New(Js::OpCode::LdArrHead, baseOpnd, arrayOpnd, m_func), offset);
- offset = Js::Constants::NoByteCodeOffset;
- opcode = Js::OpCode::StArrSegElemC;
- break;
- }
- case Js::OpCode::StArrSegItem_CI4:
- {
- baseOpnd = this->BuildSrcOpnd(baseRegSlot, TyVar);
- // This instruction must not create missing values in the array
- opcode = Js::OpCode::StArrSegElemC;
- break;
- }
- case Js::OpCode::StArrInlineItem_CI4:
- {
- baseOpnd = this->BuildSrcOpnd(baseRegSlot);
- IR::Opnd *defOpnd = baseOpnd->m_sym->m_instrDef ? baseOpnd->m_sym->m_instrDef->GetDst() : nullptr;
- if (!defOpnd)
- {
- // The array sym may be multi-def because of oddness in the renumbering of temps -- for instance,
- // if there's a loop increment expression whose result is unused (ExprGen only, probably).
- FOREACH_INSTR_BACKWARD(tmpInstr, m_func->m_exitInstr->m_prev)
- {
- if (tmpInstr->GetDst())
- {
- if (tmpInstr->GetDst()->IsEqual(baseOpnd))
- {
- defOpnd = tmpInstr->GetDst();
- break;
- }
- else if (tmpInstr->m_opcode == Js::OpCode::StElemC &&
- tmpInstr->GetDst()->AsIndirOpnd()->GetBaseOpnd()->IsEqual(baseOpnd))
- {
- defOpnd = tmpInstr->GetDst()->AsIndirOpnd()->GetBaseOpnd();
- break;
- }
- }
- }
- NEXT_INSTR_BACKWARD;
- }
- AnalysisAssert(defOpnd);
- // This instruction must not create missing values in the array
- baseOpnd->SetValueType(defOpnd->GetValueType());
- opcode = Js::OpCode::StElemC;
- break;
- }
- default:
- AssertMsg(false, "Unknown ElementUnsigned1 opcode");
- return;
- }
- indirOpnd = this->BuildIndirOpnd(baseOpnd, index);
- regOpnd = this->BuildSrcOpnd(regSlot);
- if (simpleJit)
- {
- instr = IR::JitProfilingInstr::New(opcode, indirOpnd, regOpnd, m_func);
- }
- else if(opcode == Js::OpCode::StElemC && !baseOpnd->GetValueType().IsUninitialized())
- {
- // An opnd's value type will get replaced in the forward phase when it is not fixed. Store the array type in the
- // ProfiledInstr.
- IR::ProfiledInstr *const profiledInstr = IR::ProfiledInstr::New(opcode, indirOpnd, regOpnd, m_func);
- Js::StElemInfo *const stElemInfo = JitAnew(m_func->m_alloc, Js::StElemInfo);
- stElemInfo->arrayType = baseOpnd->GetValueType();
- profiledInstr->u.stElemInfo = stElemInfo;
- instr = profiledInstr;
- }
- else
- {
- instr = IR::Instr::New(opcode, indirOpnd, regOpnd, m_func);
- }
- this->AddInstr(instr, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildArgIn
- ///
- /// Build IR instr for an ArgIn instruction.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::BuildArgIn0(uint32 offset, Js::RegSlot dstRegSlot)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(Js::OpCode::ArgIn0));
- BuildArgIn(offset, dstRegSlot, 0);
- }
- void
- IRBuilder::BuildArgIn(uint32 offset, Js::RegSlot dstRegSlot, uint16 argument)
- {
- IR::Instr * instr;
- IR::SymOpnd * srcOpnd;
- IR::RegOpnd * dstOpnd;
- StackSym * symSrc = StackSym::NewParamSlotSym(argument + 1, m_func);
- this->m_func->SetArgOffset(symSrc, (argument + LowererMD::GetFormalParamOffset()) * MachPtr);
- srcOpnd = IR::SymOpnd::New(symSrc, TyVar, m_func);
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- if (!this->m_func->IsLoopBody() && this->m_func->HasProfileInfo())
- {
- // Skip "this" pointer; "this" profile data is captured by ProfiledLdThis.
- // Subtract 1 to skip "this" pointer, subtract 1 again to get the index to index into profileData->parameterInfo.
- int paramSlotIndex = symSrc->GetParamSlotNum() - 2;
- if (paramSlotIndex >= 0)
- {
- ValueType profiledValueType;
- profiledValueType = this->m_func->GetReadOnlyProfileInfo()->GetParameterInfo(static_cast<Js::ArgSlot>(paramSlotIndex));
- dstOpnd->SetValueType(profiledValueType);
- }
- }
- instr = IR::Instr::New(Js::OpCode::ArgIn_A, dstOpnd, srcOpnd, m_func);
- this->AddInstr(instr, offset);
- }
- void
- IRBuilder::BuildArgInRest()
- {
- IR::RegOpnd * dstOpnd = this->BuildDstOpnd(m_func->GetJITFunctionBody()->GetRestParamRegSlot());
- IR::Instr *instr = IR::Instr::New(Js::OpCode::ArgIn_Rest, dstOpnd, m_func);
- this->AddInstr(instr, (uint32)-1);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildArg
- ///
- /// Build IR instr for an ArgOut instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildArgNoSrc(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_ArgNoSrc<SizePolicy>>();
- BuildArg(Js::OpCode::ArgOut_A, offset, layout->Arg, this->GetEnvRegForInnerFrameDisplay());
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildArg(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Arg<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Reg);
- }
- BuildArg(newOpcode, offset, layout->Arg, layout->Reg);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledArg(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_Arg<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Reg);
- }
- newOpcode = Js::OpCode::ArgOut_A;
- BuildArg(newOpcode, offset, layout->Arg, layout->Reg);
- }
- void
- IRBuilder::BuildArg(Js::OpCode newOpcode, uint32 offset, Js::ArgSlot argument, Js::RegSlot srcRegSlot)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::Instr * instr;
- IRType type = TyVar;
- if (newOpcode == Js::OpCode::ArgOut_ANonVar)
- {
- newOpcode = Js::OpCode::ArgOut_A;
- type = TyMachPtr;
- }
- m_argsOnStack++;
- StackSym * symDst;
- Assert(argument < USHRT_MAX);
- symDst = m_func->m_symTable->GetArgSlotSym((uint16)(argument+1));
- if (symDst == nullptr || (uint16)(argument + 1) != (argument + 1))
- {
- AssertMsg(UNREACHED, "Arg count too big...");
- Fatal();
- }
- IR::SymOpnd * dstOpnd = IR::SymOpnd::New(symDst, type, m_func);
- IR::RegOpnd * src1Opnd = this->BuildSrcOpnd(srcRegSlot, type);
- instr = IR::Instr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- this->AddInstr(instr, offset);
- m_argStack->Push(instr);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildStartCall
- ///
- /// Build IR instr for a StartCall instruction.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::BuildStartCall(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(newOpcode == Js::OpCode::StartCall);
- const unaligned Js::OpLayoutStartCall * regLayout = m_jnReader.StartCall();
- Js::ArgSlot ArgCount = regLayout->ArgCount;
- IR::Instr * instr;
- IR::RegOpnd * dstOpnd;
- // Dst of StartCall is always r0... Let's give it a new dst such that it can
- // be singleDef.
- dstOpnd = IR::RegOpnd::New(TyVar, m_func);
- #if DBG
- m_callsOnStack++;
- #endif
- IntConstType value = ArgCount;
- IR::IntConstOpnd * srcOpnd;
- srcOpnd = IR::IntConstOpnd::New(value, TyInt32, m_func);
- instr = IR::Instr::New(newOpcode, dstOpnd, srcOpnd, m_func);
- this->AddInstr(instr, offset);
- // Keep a stack of arg instructions such that we can link them up once we see
- // the call that consumes them.
- m_argStack->Push(instr);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildCallI
- ///
- /// Build IR instr for a CallI instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallI(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(Js::OpCodeUtil::IsCallOp(newOpcode) || newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjArray);
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallI<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildCallI_Helper(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, Js::Constants::NoProfileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIFlags(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(Js::OpCodeUtil::IsCallOp(newOpcode) || newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjArray);
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallIFlags<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- IR::Instr* instr = BuildCallI_Helper(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, Js::Constants::NoProfileId, layout->callFlags);
- Assert(instr->m_opcode == Js::OpCode::CallIFlags);
- if (instr->m_opcode == Js::OpCode::CallIFlags)
- {
- instr->m_opcode =
- layout->callFlags == (Js::CallFlags::CallFlags_NewTarget | Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg) ? Js::OpCode::CallINewTargetNew :
- layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallINew :
- instr->m_opcode;
- }
- }
- void IRBuilder::BuildLdSpreadIndices(uint32 offset, uint32 spreadAuxOffset)
- {
- // Link up the LdSpreadIndices instr to be the first in the arg chain. This will allow us to find it in Lowerer easier.
- IR::Opnd *auxArg = this->BuildAuxArrayOpnd(AuxArrayValue::AuxIntArray, spreadAuxOffset);
- IR::Instr *instr = IR::Instr::New(Js::OpCode::LdSpreadIndices, m_func);
- instr->SetSrc1(auxArg);
- // Create the link to the first arg.
- Js::RegSlot lastArg = m_argStack->Head()->GetDst()->AsSymOpnd()->GetStackSym()->GetArgSlotNum();
- instr->SetDst(IR::SymOpnd::New(m_func->m_symTable->GetArgSlotSym((uint16) (lastArg + 1)), TyVar, m_func));
- this->AddInstr(instr, Js::Constants::NoByteCodeOffset);
- m_argStack->Push(instr);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIExtended(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallIExtended<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->Options, layout->SpreadAuxOffset);
- }
- IR::Instr*
- IRBuilder::BuildCallIExtended(Js::OpCode newOpcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::CallIExtendedOptions options, uint32 spreadAuxOffset, Js::CallFlags flags)
- {
- if (options & Js::CallIExtended_SpreadArgs)
- {
- BuildLdSpreadIndices(offset, spreadAuxOffset);
- }
- return BuildCallI_Helper(newOpcode, offset, returnValue, function, argCount, Js::Constants::NoProfileId, flags);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- AssertMsg(false, "NYI");
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- AssertMsg(false, "NYI");
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIExtendedFlags(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_CallIExtendedFlags<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- IR::Instr* instr = BuildCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->Options, layout->SpreadAuxOffset, layout->callFlags);
- Assert(instr->m_opcode == Js::OpCode::CallIExtendedFlags);
- if (instr->m_opcode == Js::OpCode::CallIExtendedFlags)
- {
- instr->m_opcode =
- layout->callFlags == Js::CallFlags::CallFlags_ExtraArg ? Js::OpCode::CallIEval :
- layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallIExtendedNew :
- layout->callFlags == (Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg | Js::CallFlags::CallFlags_NewTarget) ? Js::OpCode::CallIExtendedNewTargetNew :
- instr->m_opcode;
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIExtendedWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- AssertMsg(false, "NYI");
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildCallIExtendedFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- AssertMsg(false, "NYI");
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIFlagsWithICIndex<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- IR::Instr* instr = BuildProfiledCallIWithICIndex(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->inlineCacheIndex);
- Assert(instr->m_opcode == Js::OpCode::CallIFlags);
- if (instr->m_opcode == Js::OpCode::CallIFlags)
- {
- instr->m_opcode =
- layout->callFlags == (Js::CallFlags::CallFlags_NewTarget | Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg) ? Js::OpCode::CallINewTargetNew :
- layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallINew :
- instr->m_opcode;
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIWithICIndex<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildProfiledCallIWithICIndex(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->inlineCacheIndex);
- }
- IR::Instr*
- IRBuilder::BuildProfiledCallIWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::ProfileId profileId, Js::InlineCacheIndex inlineCacheIndex)
- {
- return BuildProfiledCallI(opcode, offset, returnValue, function, argCount, profileId, Js::CallFlags_None, inlineCacheIndex);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIExtendedFlags(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
- || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtendedFlags<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- IR::Instr* instr = BuildProfiledCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset, layout->callFlags);
- Assert(instr->m_opcode == Js::OpCode::CallIExtendedFlags);
- if (instr->m_opcode == Js::OpCode::CallIExtendedFlags)
- {
- instr->m_opcode =
- layout->callFlags == Js::CallFlags::CallFlags_ExtraArg ? Js::OpCode::CallIEval :
- layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallIExtendedNew :
- layout->callFlags == (Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg | Js::CallFlags::CallFlags_NewTarget) ? Js::OpCode::CallIExtendedNewTargetNew :
- instr->m_opcode;
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIExtendedWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtendedWithICIndex<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildProfiledCallIExtendedWithICIndex(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset);
- }
- void
- IRBuilder::BuildProfiledCallIExtendedWithICIndex(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options, uint32 spreadAuxOffset)
- {
- BuildProfiledCallIExtended(opcode, offset, returnValue, function, argCount, profileId, options, spreadAuxOffset);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIExtendedFlagsWithICIndex(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOpWithICIndex(newOpcode) || Js::OpCodeUtil::IsProfiledCallOpWithICIndex(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtendedFlagsWithICIndex<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- IR::Instr* instr = BuildProfiledCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset);
- Assert(instr->m_opcode == Js::OpCode::CallIExtendedFlags);
- if (instr->m_opcode == Js::OpCode::CallIExtendedFlags)
- {
- instr->m_opcode =
- layout->callFlags == Js::CallFlags::CallFlags_ExtraArg ? Js::OpCode::CallIEval :
- layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallIExtendedNew :
- layout->callFlags == (Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg | Js::CallFlags::CallFlags_NewTarget) ? Js::OpCode::CallIExtendedNewTargetNew :
- instr->m_opcode;
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallI(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
- || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallI<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildProfiledCallI(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIFlags(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
- || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIFlags<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- IR::Instr* instr = BuildProfiledCallI(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->callFlags);
- Assert(instr->m_opcode == Js::OpCode::CallIFlags);
- if (instr->m_opcode == Js::OpCode::CallIFlags)
- {
- instr->m_opcode =
- layout->callFlags == (Js::CallFlags::CallFlags_NewTarget | Js::CallFlags::CallFlags_New | Js::CallFlags::CallFlags_ExtraArg) ? Js::OpCode::CallINewTargetNew :
- layout->callFlags == Js::CallFlags::CallFlags_New ? Js::OpCode::CallINew :
- instr->m_opcode;
- }
- }
- IR::Instr *
- IRBuilder::BuildProfiledCallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallFlags flags, Js::InlineCacheIndex inlineCacheIndex)
- {
- Js::OpCode newOpcode;
- ValueType returnType;
- bool isProtectedByNoProfileBailout = false;
- if (opcode == Js::OpCode::ProfiledNewScObject || opcode == Js::OpCode::ProfiledNewScObjectWithICIndex
- || opcode == Js::OpCode::ProfiledNewScObjectSpread)
- {
- newOpcode = opcode;
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(newOpcode);
- Assert(newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjectSpread);
- if (!this->m_func->HasProfileInfo())
- {
- returnType = ValueType::GetObject(ObjectType::UninitializedObject);
- }
- else
- {
- // If we have profile data, make use of it
- returnType = this->m_func->GetReadOnlyProfileInfo()->GetReturnType(opcode, profileId);
- }
- }
- else
- {
- if (this->m_func->HasProfileInfo())
- {
- returnType = this->m_func->GetReadOnlyProfileInfo()->GetReturnType(opcode, profileId);
- }
- if (opcode < Js::OpCode::ProfiledReturnTypeCallI)
- {
- newOpcode = Js::OpCodeUtil::ConvertProfiledCallOpToNonProfiled(opcode);
- if(DoBailOnNoProfile())
- {
- if(this->m_func->GetWorkItem()->GetJITTimeInfo())
- {
- const FunctionJITTimeInfo *inlinerData = this->m_func->GetWorkItem()->GetJITTimeInfo();
- if (!(this->IsLoopBody() && PHASE_OFF(Js::InlineInJitLoopBodyPhase, this->m_func))
- && inlinerData && inlinerData->GetInlineesBV())
- {
- AssertOrFailFast(profileId < inlinerData->GetInlineesBV()->Length());
- if (!inlinerData->GetInlineesBV()->Test(profileId)
- #if DBG
- || (PHASE_STRESS(Js::BailOnNoProfilePhase, this->m_func->GetTopFunc())
- && (CONFIG_FLAG(SkipFuncCountForBailOnNoProfile) < 0
- || this->m_func->m_callSiteCount >= (uint)CONFIG_FLAG(SkipFuncCountForBailOnNoProfile)))
- #endif
- )
- {
- this->InsertBailOnNoProfile(offset);
- isProtectedByNoProfileBailout = true;
- }
- }
- if (!isProtectedByNoProfileBailout)
- {
- this->callTreeHasSomeProfileInfo = true;
- }
- }
- #if DBG
- this->m_func->m_callSiteCount++;
- #endif
- }
- }
- else
- {
- // Changing this opcode into a non ReturnTypeCall* opcode is done in BuildCallI_Helper
- newOpcode = opcode;
- }
- }
- IR::Instr * callInstr = BuildCallI_Helper(newOpcode, offset, returnValue, function, argCount, profileId, flags, inlineCacheIndex);
- callInstr->isCallInstrProtectedByNoProfileBailout = isProtectedByNoProfileBailout;
- if (callInstr->GetDst() && (callInstr->GetDst()->GetValueType().IsUninitialized() || callInstr->GetDst()->GetValueType() == ValueType::UninitializedObject))
- {
- callInstr->GetDst()->SetValueType(returnType);
- }
- return callInstr;
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiledCallIExtended(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode) || Js::OpCodeUtil::IsProfiledCallOp(newOpcode)
- || Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile<Js::OpLayoutT_CallIExtended<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildProfiledCallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->Options, layout->SpreadAuxOffset);
- }
- IR::Instr *
- IRBuilder::BuildProfiledCallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::ProfileId profileId, Js::CallIExtendedOptions options,
- uint32 spreadAuxOffset, Js::CallFlags flags)
- {
- if (options & Js::CallIExtended_SpreadArgs)
- {
- BuildLdSpreadIndices(offset, spreadAuxOffset);
- }
- return BuildProfiledCallI(opcode, offset, returnValue, function, argCount, profileId, flags);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiled2CallI(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile2<Js::OpLayoutT_CallI<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildProfiled2CallI(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->profileId2);
- }
- void
- IRBuilder::BuildProfiled2CallI(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2)
- {
- Assert(opcode == Js::OpCode::ProfiledNewScObjArray || opcode == Js::OpCode::ProfiledNewScObjArraySpread);
- Js::OpCodeUtil::ConvertNonCallOpToNonProfiled(opcode);
- Js::OpCode useOpcode = opcode;
- // We either want to provide the array profile id (profileId2) to the native array creation or the call profileid (profileId)
- // to the call to NewScObject
- Js::ProfileId useProfileId = profileId2;
- Js::TypeId arrayTypeId = Js::TypeIds_Array;
- if (returnValue != Js::Constants::NoRegister)
- {
- Js::ArrayCallSiteInfo *arrayCallSiteInfo = nullptr;
- if (m_func->HasArrayInfo())
- {
- arrayCallSiteInfo = m_func->GetReadOnlyProfileInfo()->GetArrayCallSiteInfo(profileId2);
- }
- if (arrayCallSiteInfo && !m_func->IsJitInDebugMode())
- {
- if (arrayCallSiteInfo->IsNativeIntArray())
- {
- arrayTypeId = Js::TypeIds_NativeIntArray;
- }
- else if (arrayCallSiteInfo->IsNativeFloatArray())
- {
- arrayTypeId = Js::TypeIds_NativeFloatArray;
- }
- }
- else
- {
- useOpcode = (opcode == Js::OpCode::NewScObjArraySpread) ? Js::OpCode::NewScObjectSpread : Js::OpCode::NewScObject;
- useProfileId = profileId;
- }
- }
- else
- {
- useOpcode = (opcode == Js::OpCode::NewScObjArraySpread) ? Js::OpCode::NewScObjectSpread : Js::OpCode::NewScObject;
- useProfileId = profileId;
- }
- IR::Instr * callInstr = BuildCallI_Helper(useOpcode, offset, returnValue, function, argCount, useProfileId);
- if (callInstr->GetDst())
- {
- callInstr->GetDst()->SetValueType(
- ValueType::GetObject(ObjectType::Array).ToLikely().SetHasNoMissingValues(true).SetArrayTypeId(arrayTypeId));
- }
- if (callInstr->IsJitProfilingInstr())
- {
- // If we happened to decide in BuildCallI_Helper that this should be a jit profiling instr, then save the fact that it is
- // a "new Array(args, ...)" call and also save the array profile id (profileId2)
- callInstr->AsJitProfilingInstr()->isNewArray = true;
- callInstr->AsJitProfilingInstr()->arrayProfileId = profileId2;
- // Double check that this profileId made it to the JitProfilingInstr like we expect it to.
- Assert(callInstr->AsJitProfilingInstr()->profileId == profileId);
- }
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildProfiled2CallIExtended(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutDynamicProfile2<Js::OpLayoutT_CallIExtended<SizePolicy>>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Return);
- this->DoClosureRegCheck(layout->Function);
- }
- BuildProfiled2CallIExtended(newOpcode, offset, layout->Return, layout->Function, layout->ArgCount, layout->profileId, layout->profileId2, layout->Options, layout->SpreadAuxOffset);
- }
- void
- IRBuilder::BuildProfiled2CallIExtended(Js::OpCode opcode, uint32 offset, Js::RegSlot returnValue, Js::RegSlot function,
- Js::ArgSlot argCount, Js::ProfileId profileId, Js::ProfileId profileId2,
- Js::CallIExtendedOptions options, uint32 spreadAuxOffset)
- {
- if (options & Js::CallIExtended_SpreadArgs)
- {
- BuildLdSpreadIndices(offset, spreadAuxOffset);
- }
- BuildProfiled2CallI(opcode, offset, returnValue, function, argCount, profileId, profileId2);
- }
- IR::Instr *
- 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)
- {
- IR::Instr * instr;
- IR::RegOpnd * dstOpnd;
- IR::RegOpnd * src1Opnd;
- StackSym * symDst;
- src1Opnd = this->BuildSrcOpnd(Src1RegSlot);
- if (dstRegSlot == Js::Constants::NoRegister)
- {
- dstOpnd = nullptr;
- symDst = nullptr;
- }
- else
- {
- dstOpnd = this->BuildDstOpnd(dstRegSlot);
- symDst = dstOpnd->m_sym;
- }
- const bool jitProfiling = m_func->DoSimpleJitDynamicProfile();
- bool profiledReturn = false;
- if (Js::OpCodeUtil::IsProfiledReturnTypeCallOp(newOpcode))
- {
- profiledReturn = true;
- newOpcode = Js::OpCodeUtil::ConvertProfiledReturnTypeCallOpToNonProfiled(newOpcode);
- // If we're profiling in the jitted code we want to propagate the profileId
- // If we're using profile data instead of collecting it, we don't want to
- // use the profile data from a return type call (this was previously done in IRBuilder::BuildProfiledCallI)
- if (!jitProfiling)
- {
- profileId = Js::Constants::NoProfileId;
- }
- }
- if (profileId != Js::Constants::NoProfileId)
- {
- if (jitProfiling)
- {
- // In SimpleJit we want this call to be a profiled call after being jitted
- instr = IR::JitProfilingInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr->AsJitProfilingInstr()->profileId = profileId;
- instr->AsJitProfilingInstr()->isProfiledReturnCall = profiledReturn;
- instr->AsJitProfilingInstr()->inlineCacheIndex = inlineCacheIndex;
- }
- else
- {
- instr = IR::ProfiledInstr::New(newOpcode, dstOpnd, src1Opnd, m_func);
- instr->AsProfiledInstr()->u.profileId = profileId;
- }
- }
- else
- {
- instr = IR::Instr::New(newOpcode, m_func);
- instr->SetSrc1(src1Opnd);
- if (dstOpnd != nullptr)
- {
- instr->SetDst(dstOpnd);
- }
- }
- if (dstOpnd && newOpcode == Js::OpCode::NewScObject)
- {
- dstOpnd->SetValueType(ValueType::GetObject(ObjectType::UninitializedObject));
- }
- if (symDst && symDst->m_isSingleDef)
- {
- switch (instr->m_opcode)
- {
- case Js::OpCode::NewScObject:
- case Js::OpCode::NewScObjectSpread:
- case Js::OpCode::NewScObjectLiteral:
- case Js::OpCode::NewScObjArray:
- case Js::OpCode::NewScObjArraySpread:
- symDst->m_isSafeThis = true;
- symDst->m_isNotNumber = true;
- break;
- }
- }
- this->AddInstr(instr, offset);
- this->BuildCallCommon(instr, symDst, ArgCount, flags);
- return instr;
- }
- void
- IRBuilder::BuildCallCommon(IR::Instr * instr, StackSym * symDst, Js::ArgSlot argCount, Js::CallFlags flags)
- {
- Js::OpCode newOpcode = instr->m_opcode;
- IR::Instr * argInstr = nullptr;
- IR::Instr * prevInstr = instr;
- #if DBG
- int count = 0;
- #endif
- // Link all the args of this call by creating a def/use chain through the src2.
- AssertOrFailFast(!m_argStack->Empty());
- for (argInstr = m_argStack->Pop();
- argInstr && !m_argStack->Empty() && argInstr->m_opcode != Js::OpCode::StartCall;
- argInstr = m_argStack->Pop())
- {
- prevInstr->SetSrc2(argInstr->GetDst());
- prevInstr = argInstr;
- #if DBG
- count++;
- #endif
- }
- AssertOrFailFast(argInstr == nullptr || argInstr->m_opcode == Js::OpCode::StartCall);
- if (m_argStack->Empty())
- {
- this->callTreeHasSomeProfileInfo = false;
- }
- if (newOpcode == Js::OpCode::NewScObject || newOpcode == Js::OpCode::NewScObjArray
- || newOpcode == Js::OpCode::NewScObjectSpread || newOpcode == Js::OpCode::NewScObjArraySpread)
- {
- #if DBG
- count++;
- #endif
- m_argsOnStack++;
- }
- argCount = Js::CallInfo::GetArgCountWithExtraArgs(flags, argCount);
- if (argInstr)
- {
- prevInstr->SetSrc2(argInstr->GetDst());
- AssertMsg(instr->m_prev->m_opcode == Js::OpCode::LdSpreadIndices
- // All non-spread calls need StartCall to have the same number of args
- || (argInstr->GetSrc1()->IsIntConstOpnd()
- && argInstr->GetSrc1()->AsIntConstOpnd()->GetValue() == count
- && count == argCount), "StartCall has wrong number of arguments...");
- }
- else
- {
- AssertMsg(false, "Expect StartCall on other opcodes...");
- }
- // Update Func if this is the highest amount of stack we've used so far
- // to push args.
- #if DBG
- m_callsOnStack--;
- #endif
- if (m_func->m_argSlotsForFunctionsCalled < m_argsOnStack)
- m_func->m_argSlotsForFunctionsCalled = m_argsOnStack;
- #if DBG
- if (m_callsOnStack == 0)
- Assert(m_argsOnStack == argCount);
- #endif
- m_argsOnStack -= argCount;
- if (m_func->IsJitInDebugMode())
- {
- // Insert bailout after return from a call, script or library function call.
- this->InsertBailOutForDebugger(
- m_jnReader.GetCurrentOffset(), // bailout will resume at the offset of next instr.
- c_debuggerBailOutKindForCall);
- }
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildClass
- ///
- /// Build IR instr for an InitClass instruction.
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildClass(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_Class<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->Constructor);
- this->DoClosureRegCheck(layout->Extends);
- }
- BuildClass(newOpcode, offset, layout->Constructor, layout->Extends);
- }
- void
- IRBuilder::BuildClass(Js::OpCode newOpcode, uint32 offset, Js::RegSlot constructor, Js::RegSlot extends)
- {
- Assert(newOpcode == Js::OpCode::InitClass);
- IR::Instr * insn = IR::Instr::New(newOpcode, m_func);
- insn->SetSrc1(this->BuildSrcOpnd(constructor));
- if (extends != Js::Constants::NoRegister)
- {
- insn->SetSrc2(this->BuildSrcOpnd(extends));
- }
- this->AddInstr(insn, offset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildBrReg1
- ///
- /// Build IR instr for a BrReg1 instruction.
- /// This is a conditional branch with a single source operand (e.g., "if (x)" ...)
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildBrReg1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_BrReg1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R1);
- }
- BuildBrReg1(newOpcode, offset, m_jnReader.GetCurrentOffset() + layout->RelativeJumpOffset, layout->R1);
- }
- void
- IRBuilder::BuildBrReg1(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot srcRegSlot)
- {
- IR::BranchInstr * branchInstr;
- IR::RegOpnd * srcOpnd;
- srcOpnd = this->BuildSrcOpnd(srcRegSlot);
- if (newOpcode == Js::OpCode::BrNotUndecl_A) {
- IR::AddrOpnd *srcOpnd2 = IR::AddrOpnd::New(m_func->GetScriptContextInfo()->GetUndeclBlockVarAddr(),
- IR::AddrOpndKindDynamicVar, this->m_func);
- branchInstr = IR::BranchInstr::New(Js::OpCode::BrNotAddr_A, nullptr, srcOpnd, srcOpnd2, m_func);
- } else {
- branchInstr = IR::BranchInstr::New(newOpcode, nullptr, srcOpnd, m_func);
- }
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildBrReg2
- ///
- /// Build IR instr for a BrReg2 instruction.
- /// This is a conditional branch with a 2 source operands (e.g., "if (x == y)" ...)
- ///
- ///----------------------------------------------------------------------------
- template <typename SizePolicy>
- void
- IRBuilder::BuildBrReg2(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_BrReg2<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R1);
- this->DoClosureRegCheck(layout->R2);
- }
- BuildBrReg2(newOpcode, offset, m_jnReader.GetCurrentOffset() + layout->RelativeJumpOffset, layout->R1, layout->R2);
- }
- template <typename SizePolicy>
- void
- IRBuilder::BuildBrReg1Unsigned1(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(newOpcode == Js::OpCode::BrOnEmpty
- /* || newOpcode == Js::OpCode::BrOnNotEmpty */ // BrOnNotEmpty not generate by the byte code
- );
- Assert(!OpCodeAttr::IsProfiledOp(newOpcode));
- Assert(OpCodeAttr::HasMultiSizeLayout(newOpcode));
- auto layout = m_jnReader.GetLayout<Js::OpLayoutT_BrReg1Unsigned1<SizePolicy>>();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(layout->R1);
- }
- BuildBrBReturn(newOpcode, offset, layout->R1, layout->C2, m_jnReader.GetCurrentOffset() + layout->RelativeJumpOffset);
- }
- void
- IRBuilder::BuildBrBReturn(Js::OpCode newOpcode, uint32 offset, Js::RegSlot DestRegSlot, uint32 forInLoopLevel, uint32 targetOffset)
- {
- IR::Opnd *srcOpnd = this->BuildForInEnumeratorOpnd(forInLoopLevel);
- IR::RegOpnd * destOpnd = this->BuildDstOpnd(DestRegSlot);
- IR::BranchInstr * branchInstr = IR::BranchInstr::New(newOpcode, destOpnd, nullptr, srcOpnd, m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- switch (newOpcode)
- {
- case Js::OpCode::BrOnEmpty:
- destOpnd->SetValueType(ValueType::String);
- break;
- default:
- Assert(false);
- break;
- };
- }
- void
- IRBuilder::BuildBrReg2(Js::OpCode newOpcode, uint32 offset, uint targetOffset, Js::RegSlot R1, Js::RegSlot R2)
- {
- IR::BranchInstr * branchInstr;
- if (newOpcode == Js::OpCode::BrOnEmpty
- /* || newOpcode == Js::OpCode::BrOnNotEmpty */ // BrOnNotEmpty not generate by the byte code
- )
- {
- BuildBrBReturn(newOpcode, offset, R1, R2, targetOffset);
- return;
- }
- IR::RegOpnd * src1Opnd;
- IR::RegOpnd * src2Opnd;
- src1Opnd = this->BuildSrcOpnd(R1);
- src2Opnd = this->BuildSrcOpnd(R2);
- if (newOpcode == Js::OpCode::Case)
- {
- // generating branches for Cases is entirely handled
- // by the SwitchIRBuilder
- m_switchBuilder.OnCase(src1Opnd, src2Opnd, offset, targetOffset);
- #ifdef BYTECODE_BRANCH_ISLAND
- // Make sure that if there are branch island between the cases, we consume it first
- EnsureConsumeBranchIsland();
- #endif
- // some instructions can't be optimized past, such as LdFld for objects. In these cases we have
- // to inform the SwitchBuilder to flush any optimized cases that it has stored up to this point
- // peeks the next opcode - to check if it is not a case statement (for example: the next instr can be a LdFld for objects)
- Js::OpCode peekOpcode = m_jnReader.PeekOp();
- if (peekOpcode != Js::OpCode::Case && peekOpcode != Js::OpCode::EndSwitch)
- {
- m_switchBuilder.FlushCases(m_jnReader.GetCurrentOffset());
- }
- }
- else
- {
- branchInstr = IR::BranchInstr::New(newOpcode, nullptr, src1Opnd, src2Opnd, m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- }
- void
- IRBuilder::BuildEmpty(Js::OpCode newOpcode, uint32 offset)
- {
- IR::Instr *instr;
- m_jnReader.Empty();
- instr = IR::Instr::New(newOpcode, m_func);
- switch (newOpcode)
- {
- case Js::OpCode::CommitScope:
- {
- IR::RegOpnd * src1Opnd;
- src1Opnd = this->BuildSrcOpnd(m_func->GetJITFunctionBody()->GetLocalClosureReg());
- IR::LabelInstr *labelNull = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
- IR::RegOpnd * funcExprOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::LdFuncExpr, funcExprOpnd, m_func);
- this->AddInstr(instr, offset);
- IR::BranchInstr *branchInstr = IR::BranchInstr::New(Js::OpCode::BrFncCachedScopeNeq, labelNull,
- funcExprOpnd, src1Opnd, this->m_func);
- this->AddInstr(branchInstr, offset);
- instr = IR::Instr::New(newOpcode, this->m_func);
- instr->SetSrc1(src1Opnd);
- this->AddInstr(instr, offset);
- this->AddInstr(labelNull, Js::Constants::NoByteCodeOffset);
- return;
- }
- case Js::OpCode::Ret:
- {
- IR::RegOpnd *regOpnd = BuildDstOpnd(0);
- instr->SetSrc1(regOpnd);
- this->AddInstr(instr, offset);
- break;
- }
- case Js::OpCode::Leave:
- {
- IR::BranchInstr * branchInstr;
- IR::LabelInstr * labelInstr;
- if (this->handlerOffsetStack && !this->handlerOffsetStack->Empty() && this->handlerOffsetStack->Top().Second())
- {
- // If the try region has a break block, we don't want the Flowgraph to move all of that code out of the loop
- // because an exception will bring the control back into the loop. The branch out of the loop (which is the
- // reason for the code to be a break block) can still be moved out though.
- //
- // "BrOnException $catch" is inserted before Leave's in the try region to instrument flow from the try region
- // to the catch region (which is in the loop).
- IR::BranchInstr * brOnException = IR::BranchInstr::New(Js::OpCode::BrOnException, nullptr, this->m_func);
- this->AddBranchInstr(brOnException, offset, this->handlerOffsetStack->Top().First());
- }
- labelInstr = IR::LabelInstr::New(Js::OpCode::Label, this->m_func);
- branchInstr = IR::BranchInstr::New(newOpcode, labelInstr, this->m_func);
- this->AddInstr(branchInstr, offset);
- this->AddInstr(labelInstr, Js::Constants::NoByteCodeOffset);
- break;
- }
- case Js::OpCode::LeaveNull:
- finallyBlockLevel--;
- this->AddInstr(instr, offset);
- break;
- case Js::OpCode::Finally:
- if (this->handlerOffsetStack)
- {
- AssertOrFailFast(!this->handlerOffsetStack->Empty());
- AssertOrFailFast(this->handlerOffsetStack->Top().Second() == false);
- this->handlerOffsetStack->Pop();
- }
- finallyBlockLevel++;
- this->AddInstr(IR::Instr::New(Js::OpCode::Finally, this->m_func), offset);
- break;
- case Js::OpCode::Break:
- if (m_func->IsJitInDebugMode())
- {
- // Add explicit bailout.
- this->InsertBailOutForDebugger(offset, IR::BailOutExplicit);
- }
- else
- {
- // Default behavior, let's keep it for now, removed in lowerer.
- this->AddInstr(instr, offset);
- }
- break;
- case Js::OpCode::BeginBodyScope:
- {
- // This marks the end of a param socpe which is not merged with body scope.
- // So we have to first cache the closure so that we can use it to copy the initial values for
- // body syms from corresponding param syms (LdParamSlot). Body should get its own scope slot.
- Assert(!this->IsParamScopeDone());
- this->SetParamScopeDone();
- IR::Opnd * localClosureOpnd;
- if (this->m_func->GetLocalClosureSym() != nullptr)
- {
- localClosureOpnd = IR::RegOpnd::New(this->m_func->GetLocalClosureSym(), TyVar, this->m_func);
- }
- else
- {
- AssertOrFailFast(this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() == 0 && !this->m_func->GetJITFunctionBody()->HasScopeObject());
- localClosureOpnd = IR::IntConstOpnd::New(0, TyVar, this->m_func);
- }
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::Ld_A,
- this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetParamClosureReg()),
- localClosureOpnd,
- this->m_func),
- offset);
- // Create a new local closure for the body when either body scope has scope slots allocated or
- // eval is present which can leak declarations.
- if (this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() > 0 || this->m_func->GetJITFunctionBody()->HasScopeObject())
- {
- if (this->m_func->GetJITFunctionBody()->HasScopeObject())
- {
- if (this->m_func->GetJITFunctionBody()->HasCachedScopePropIds())
- {
- this->BuildInitCachedScope(0, Js::Constants::NoByteCodeOffset);
- }
- else
- {
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::NewScopeObject,
- this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
- m_func),
- Js::Constants::NoByteCodeOffset);
- }
- }
- else
- {
- this->AddInstr(
- IR::Instr::New(
- Js::OpCode::NewScopeSlots,
- this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
- IR::IntConstOpnd::New(this->m_func->GetJITFunctionBody()->GetScopeSlotArraySize() + Js::ScopeSlots::FirstSlotIndex, TyUint32, this->m_func),
- m_func),
- Js::Constants::NoByteCodeOffset);
- }
- IR::Instr* lfd = IR::Instr::New(
- Js::OpCode::LdFrameDisplay,
- this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
- this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalClosureReg()),
- this->BuildDstOpnd(this->m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg()),
- this->m_func);
- this->AddInstr(
- lfd,
- Js::Constants::NoByteCodeOffset);
- lfd->isNonFastPathFrameDisplay = true;
- }
- break;
- }
- default:
- this->AddInstr(instr, offset);
- break;
- }
- }
- #ifdef BYTECODE_BRANCH_ISLAND
- void
- IRBuilder::EnsureConsumeBranchIsland()
- {
- if (m_jnReader.PeekOp() == Js::OpCode::Br)
- {
- // Save the old offset
- uint offset = m_jnReader.GetCurrentOffset();
- // Read the potentially a branch around
- Js::LayoutSize layoutSize;
- Js::OpCode opcode = m_jnReader.ReadOp(layoutSize);
- Assert(opcode == Js::OpCode::Br);
- Assert(layoutSize == Js::SmallLayout);
- const unaligned Js::OpLayoutBr * playout = m_jnReader.Br();
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + playout->RelativeJumpOffset;
- uint branchIslandOffset = m_jnReader.GetCurrentOffset();
- if (branchIslandOffset == targetOffset)
- {
- // branch to next, there is no long branch
- m_jnReader.SetCurrentOffset(offset);
- return;
- }
- // Ignore all the BrLong
- while (m_jnReader.PeekOp() == Js::OpCode::BrLong)
- {
- opcode = m_jnReader.ReadOp(layoutSize);
- Assert(opcode == Js::OpCode::BrLong);
- Assert(layoutSize == Js::SmallLayout);
- m_jnReader.BrLong();
- }
- // Confirm that is a branch around
- if ((uint)m_jnReader.GetCurrentOffset() == targetOffset)
- {
- // Really consume the branch island
- m_jnReader.SetCurrentOffset(branchIslandOffset);
- ConsumeBranchIsland();
- // Mark the virtual branch around as a redirect long branch as well
- // so that if it is the target of another branch, it will just keep pass
- // the branch island
- Assert(longBranchMap);
- Assert(offset < m_offsetToInstructionCount);
- Assert(m_offsetToInstruction[offset] == nullptr);
- m_offsetToInstruction[offset] = VirtualLongBranchInstr;
- longBranchMap->Add(offset, targetOffset);
- }
- else
- {
- // Reset the offset
- m_jnReader.SetCurrentOffset(offset);
- }
- }
- }
- IR::Instr * const IRBuilder::VirtualLongBranchInstr = (IR::Instr *)-1;
- void
- IRBuilder::ConsumeBranchIsland()
- {
- do
- {
- uint32 offset = m_jnReader.GetCurrentOffset();
- Js::LayoutSize layoutSize;
- Js::OpCode opcode = m_jnReader.ReadOp(layoutSize);
- Assert(opcode == Js::OpCode::BrLong);
- Assert(layoutSize == Js::SmallLayout);
- BuildBrLong(Js::OpCode::BrLong, offset);
- }
- while (m_jnReader.PeekOp() == Js::OpCode::BrLong);
- }
- void
- IRBuilder::BuildBrLong(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(newOpcode == Js::OpCode::BrLong);
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- Assert(offset != Js::Constants::NoByteCodeOffset);
- const unaligned Js::OpLayoutBrLong *branchInsn = m_jnReader.BrLong();
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
- Assert(offset < m_offsetToInstructionCount);
- Assert(m_offsetToInstruction[offset] == nullptr);
- // BrLong are also just the target of another branch, just set a virtual long branch instr
- // and remap the original branch to the actual destination in ResolveVirtualLongBranch
- m_offsetToInstruction[offset] = VirtualLongBranchInstr;
- longBranchMap->Add(offset, targetOffset);
- }
- uint
- IRBuilder::ResolveVirtualLongBranch(IR::BranchInstr * branchInstr, uint offset)
- {
- Assert(longBranchMap);
- uint32 targetOffset;
- if (!longBranchMap->TryGetValue(offset, &targetOffset))
- {
- // If we see a VirtualLongBranchInstr, we must have a mapping to the real target offset
- Assert(false);
- Fatal();
- }
- // If this is a jump out of the loop body we need to load the return IP and jump to the loop exit instead
- if (!IsLoopBodyOuterOffset(targetOffset))
- {
- return targetOffset;
- }
- // Multi branch shouldn't be exiting a loop
- Assert(branchInstr->m_opcode != Js::OpCode::MultiBr);
- // Don't load the return IP if it is already loaded (for the case of early exit)
- if (!IsLoopBodyReturnIPInstr(branchInstr->m_prev))
- {
- IR::Instr * returnIPInstr = CreateLoopBodyReturnIPInstr(targetOffset, branchInstr->GetByteCodeOffset());
- // Any jump to this branch to jump to the return IP load instr first
- uint32 branchInstrByteCodeOffset = branchInstr->GetByteCodeOffset();
- Assert(this->m_offsetToInstruction[branchInstrByteCodeOffset] == branchInstr ||
- (this->m_offsetToInstruction[branchInstrByteCodeOffset]->HasBailOutInfo() &&
- this->m_offsetToInstruction[branchInstrByteCodeOffset]->GetBailOutKind() == IR::BailOutInjected));
- InsertInstr(returnIPInstr, branchInstr);
- }
- return GetLoopBodyExitInstrOffset();
- }
- #endif
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildBr
- ///
- /// Build IR instr for a Br (unconditional branch) instruction.
- /// or TryCatch/TryFinally
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::BuildBr(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::BranchInstr * branchInstr;
- const unaligned Js::OpLayoutBr *branchInsn = m_jnReader.Br();
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
- #ifdef BYTECODE_BRANCH_ISLAND
- bool isLongBranchIsland = (m_jnReader.PeekOp() == Js::OpCode::BrLong);
- if (isLongBranchIsland)
- {
- ConsumeBranchIsland();
- }
- #endif
- if(newOpcode == Js::OpCode::EndSwitch)
- {
- m_switchBuilder.EndSwitch(offset, targetOffset);
- return;
- }
- #ifdef PERF_HINT
- else if (PHASE_TRACE1(Js::PerfHintPhase) && (newOpcode == Js::OpCode::TryCatch || newOpcode == Js::OpCode::TryFinally) )
- {
- WritePerfHint(PerfHints::HasTryBlock, this->m_func, offset);
- }
- #endif
- #ifdef BYTECODE_BRANCH_ISLAND
- if (isLongBranchIsland && (targetOffset == (uint)m_jnReader.GetCurrentOffset()))
- {
- // Branch to next (probably after consume branch island), try to not emit the branch
- // Mark the jump around instruction as a virtual long branch as well so we can just
- // fall through instead of branch to exit
- Assert(offset < m_offsetToInstructionCount);
- if (m_offsetToInstruction[offset] == nullptr)
- {
- m_offsetToInstruction[offset] = VirtualLongBranchInstr;
- longBranchMap->Add(offset, targetOffset);
- return;
- }
- // We may have already create an instruction on this offset as a statement boundary
- // or in the bailout at every byte code case.
- // The statement boundary case only happens if we have emitted the long branch island
- // after an existing no fall through instruction, but that instruction also happen to be
- // branch to next. We will just generate an actual branch to next instruction.
- Assert(m_offsetToInstruction[offset]->m_opcode == Js::OpCode::StatementBoundary
- || (Js::Configuration::Global.flags.IsEnabled(Js::BailOutAtEveryByteCodeFlag)
- && m_offsetToInstruction[offset]->m_opcode == Js::OpCode::BailOnEqual));
- }
- #endif
- if ((newOpcode == Js::OpCode::TryCatch) && this->handlerOffsetStack)
- {
- this->handlerOffsetStack->Push(Pair<uint, bool>(targetOffset, true));
- }
- else if ((newOpcode == Js::OpCode::TryFinally) && this->handlerOffsetStack)
- {
- this->handlerOffsetStack->Push(Pair<uint, bool>(targetOffset, false));
- }
- branchInstr = IR::BranchInstr::New(newOpcode, nullptr, m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- void
- IRBuilder::BuildBrS(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- IR::BranchInstr * branchInstr;
- const unaligned Js::OpLayoutBrS *branchInsn = m_jnReader.BrS();
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
- branchInstr = IR::BranchInstr::New(newOpcode, nullptr,
- IR::IntConstOpnd::New(branchInsn->val,
- TyInt32, m_func),m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildBrProperty
- ///
- /// Build IR instr for a BrProperty instruction.
- /// This is a conditional branch that tests whether the given property
- /// is present on the given instance.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::BuildBrProperty(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- const unaligned Js::OpLayoutBrProperty *branchInsn = m_jnReader.BrProperty();
- if (!PHASE_OFF(Js::ClosureRegCheckPhase, m_func))
- {
- this->DoClosureRegCheck(branchInsn->Instance);
- }
- IR::BranchInstr * branchInstr;
- Js::PropertyId propertyId =
- m_func->GetJITFunctionBody()->GetReferencedPropertyId(branchInsn->PropertyIdIndex);
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
- IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, branchInsn->Instance, propertyId, branchInsn->PropertyIdIndex, PropertyKindData);
- branchInstr = IR::BranchInstr::New(newOpcode, nullptr, fieldSymOpnd, m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- void
- IRBuilder::BuildBrLocalProperty(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- switch (newOpcode)
- {
- case Js::OpCode::BrOnNoLocalProperty:
- newOpcode = Js::OpCode::BrOnNoProperty;
- break;
- default:
- Assert(0);
- break;
- }
- const unaligned Js::OpLayoutBrLocalProperty *branchInsn = m_jnReader.BrLocalProperty();
- if (m_func->GetLocalClosureSym()->HasByteCodeRegSlot())
- {
- IR::ByteCodeUsesInstr * byteCodeUse = IR::ByteCodeUsesInstr::New(m_func, offset);
- byteCodeUse->SetNonOpndSymbol(m_func->GetLocalClosureSym()->m_id);
- this->AddInstr(byteCodeUse, offset);
- }
- IR::BranchInstr * branchInstr;
- Js::PropertyId propertyId =
- m_func->GetJITFunctionBody()->GetReferencedPropertyId(branchInsn->PropertyIdIndex);
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;
- IR::SymOpnd * fieldSymOpnd = this->BuildFieldOpnd(newOpcode, m_func->GetJITFunctionBody()->GetLocalClosureReg(), propertyId, branchInsn->PropertyIdIndex, PropertyKindData);
- branchInstr = IR::BranchInstr::New(newOpcode, nullptr, fieldSymOpnd, m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- void
- IRBuilder::BuildBrEnvProperty(Js::OpCode newOpcode, uint32 offset)
- {
- Assert(!OpCodeAttr::HasMultiSizeLayout(newOpcode));
- const unaligned Js::OpLayoutBrEnvProperty *branchInsn = m_jnReader.BrEnvProperty();
- IR::Instr *instr;
- IR::BranchInstr * branchInstr;
- IR::RegOpnd *regOpnd;
- IR::SymOpnd *fieldOpnd;
- PropertySym *fieldSym;
- fieldOpnd = this->BuildFieldOpnd(Js::OpCode::LdSlotArr, this->GetEnvReg(), branchInsn->SlotIndex, (Js::PropertyIdIndexType)-1, PropertyKindSlotArray);
- regOpnd = IR::RegOpnd::New(TyVar, m_func);
- instr = IR::Instr::New(Js::OpCode::LdSlotArr, regOpnd, fieldOpnd, m_func);
- this->AddInstr(instr, offset);
- Js::PropertyId propertyId =
- m_func->GetJITFunctionBody()->GetReferencedPropertyId(branchInsn->PropertyIdIndex);
- unsigned int targetOffset = m_jnReader.GetCurrentOffset() + branchInsn->RelativeJumpOffset;\
- fieldSym = PropertySym::New(regOpnd->m_sym, propertyId, branchInsn->PropertyIdIndex, (uint)-1, PropertyKindData, m_func);
- fieldOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- branchInstr = IR::BranchInstr::New(Js::OpCode::BrOnNoProperty, nullptr, fieldOpnd, m_func);
- this->AddBranchInstr(branchInstr, offset, targetOffset);
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::AddBranchInstr
- ///
- /// Create a branch/offset pair which will be fixed up at the end of the
- /// IRBuilder phase and add the instruction
- ///
- ///----------------------------------------------------------------------------
- BranchReloc *
- IRBuilder::AddBranchInstr(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset)
- {
- AssertOrFailFast(targetOffset <= m_func->GetJITFunctionBody()->GetByteCodeLength());
- //
- // Loop jitting would be done only till the LoopEnd
- // Any branches beyond that offset are for the return stmt
- //
- if (IsLoopBodyOuterOffset(targetOffset))
- {
- // if we have loaded the loop IP sym from the ProfiledLoopEnd then don't add it here
- if (!IsLoopBodyReturnIPInstr(m_lastInstr))
- {
- this->InsertLoopBodyReturnIPInstr(targetOffset, offset);
- }
- // Jump the restore StSlot and Ret instruction
- targetOffset = GetLoopBodyExitInstrOffset();
- }
- BranchReloc * reloc = nullptr;
- reloc = this->CreateRelocRecord(branchInstr, offset, targetOffset);
- this->AddInstr(branchInstr, offset);
- return reloc;
- }
- BranchReloc *
- IRBuilder::CreateRelocRecord(IR::BranchInstr * branchInstr, uint32 offset, uint32 targetOffset)
- {
- BranchReloc * reloc = JitAnew(this->m_tempAlloc, BranchReloc, branchInstr, offset, targetOffset);
- this->branchRelocList->Prepend(reloc);
- return reloc;
- }
- ///----------------------------------------------------------------------------
- ///
- /// IRBuilder::BuildRegexFromPattern
- ///
- /// Build a new RegEx instruction. Simply construct a var to hold the regex
- /// and load it as an immediate into a register.
- ///
- ///----------------------------------------------------------------------------
- void
- IRBuilder::BuildRegexFromPattern(Js::RegSlot dstRegSlot, uint32 patternIndex, uint32 offset)
- {
- IR::Instr * instr;
- IR::RegOpnd* dstOpnd = this->BuildDstOpnd(dstRegSlot);
- dstOpnd->SetValueType(ValueType::GetObject(ObjectType::RegExp));
- IR::Opnd * regexOpnd = IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetLiteralRegexAddr(patternIndex), IR::AddrOpndKindDynamicMisc, this->m_func);
- instr = IR::Instr::New(Js::OpCode::NewRegEx, dstOpnd, regexOpnd, this->m_func);
- this->AddInstr(instr, offset);
- }
- bool
- IRBuilder::IsFloatFunctionCallsite(Js::BuiltinFunction index, size_t argc)
- {
- return Js::JavascriptLibrary::IsFloatFunctionCallsite(index, argc);
- }
- void
- IRBuilder::CheckBuiltIn(PropertySym * propertySym, Js::BuiltinFunction *puBuiltInIndex)
- {
- Js::BuiltinFunction index = Js::BuiltinFunction::None;
- // Check whether the propertySym appears to be a built-in.
- if (propertySym->m_fieldKind != PropertyKindData)
- {
- return;
- }
- index = Js::JavascriptLibrary::GetBuiltinFunctionForPropId(propertySym->m_propertyId);
- if (index == Js::BuiltinFunction::None)
- {
- return;
- }
- // If the target is one of the Math built-ins, see whether the stack sym is the
- // global "Math".
- if (Js::JavascriptLibrary::IsFltFunc(index))
- {
- if (!propertySym->m_stackSym->m_isSingleDef)
- {
- return;
- }
- IR::Instr *instr = propertySym->m_stackSym->m_instrDef;
- AssertMsg(instr != nullptr, "Single-def stack sym w/o def instr?");
- if (instr->m_opcode != Js::OpCode::LdRootFld && instr->m_opcode != Js::OpCode::LdRootFldForTypeOf)
- {
- return;
- }
- IR::Opnd * opnd = instr->GetSrc1();
- AssertMsg(opnd != nullptr && opnd->IsSymOpnd() && opnd->AsSymOpnd()->m_sym->IsPropertySym(),
- "LdRootFld w/o propertySym src?");
- if (opnd->AsSymOpnd()->m_sym->AsPropertySym()->m_propertyId != Js::PropertyIds::Math)
- {
- return;
- }
- }
- *puBuiltInIndex = index;
- }
- StackSym *
- IRBuilder::EnsureStackFuncPtrSym()
- {
- StackSym * sym = this->m_stackFuncPtrSym;
- if (sym)
- {
- return sym;
- }
- if (m_func->IsLoopBody() && m_func->DoStackNestedFunc())
- {
- Assert(m_func->IsTopFunc());
- sym = StackSym::New(TyVar, m_func);
- this->m_stackFuncPtrSym = sym;
- }
- return sym;
- }
- void
- IRBuilder::GenerateLoopBodySlotAccesses(uint offset)
- {
- //
- // The interpreter instance is passed as 0th argument to the JITted loop body function.
- // Always load the argument, then use it to generate any necessary store-slots.
- //
- uint16 argument = 0;
- StackSym *symSrc = StackSym::NewParamSlotSym(argument + 1, m_func);
- symSrc->m_offset = (argument + LowererMD::GetFormalParamOffset()) * MachPtr;
- symSrc->m_allocated = true;
- m_func->SetHasImplicitParamLoad();
- IR::SymOpnd *srcOpnd = IR::SymOpnd::New(symSrc, TyVar, m_func);
- StackSym *loopParamSym = m_func->EnsureLoopParamSym();
- IR::RegOpnd *loopParamOpnd = IR::RegOpnd::New(loopParamSym, TyMachPtr, m_func);
- IR::Instr *instrArgIn = IR::Instr::New(Js::OpCode::ArgIn_A, loopParamOpnd, srcOpnd, m_func);
- m_func->m_headInstr->InsertAfter(instrArgIn);
- StackSym *stackFuncPtrSym = this->m_stackFuncPtrSym;
- if (stackFuncPtrSym)
- {
- PropertySym * fieldSym = PropertySym::FindOrCreate(loopParamSym->m_id, (Js::PropertyId)(Js::InterpreterStackFrame::GetOffsetOfStackNestedFunctions() / sizeof(Js::Var)), (uint32)-1, (uint)-1, PropertyKindLocalSlots, m_func);
- IR::SymOpnd * opndPtrRef = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- IR::Instr * instrPtrInit = IR::Instr::New(Js::OpCode::LdSlot, IR::RegOpnd::New(stackFuncPtrSym, TyVar, m_func), opndPtrRef, m_func);
- instrArgIn->InsertAfter(instrPtrInit);
- }
- GenerateLoopBodyStSlots(loopParamSym->m_id, offset);
- }
- void
- IRBuilder::GenerateLoopBodyStSlots(SymID loopParamSymId, uint offset)
- {
- if (this->m_stSlots->Count() == 0)
- {
- return;
- }
- FOREACH_BITSET_IN_FIXEDBV(regSlot, this->m_stSlots)
- {
- this->GenerateLoopBodyStSlot(regSlot, offset);
- }
- NEXT_BITSET_IN_FIXEDBV;
- }
- IR::Instr *
- IRBuilder::GenerateLoopBodyStSlot(Js::RegSlot regSlot, uint offset)
- {
- Assert(!this->RegIsConstant((Js::RegSlot)regSlot));
- StackSym *loopParamSym = m_func->EnsureLoopParamSym();
- PropertySym * fieldSym = PropertySym::FindOrCreate(loopParamSym->m_id, (Js::PropertyId)(regSlot + this->m_loopBodyLocalsStartSlot), (uint32)-1, (uint)-1, PropertyKindLocalSlots, m_func);
- IR::SymOpnd * fieldSymOpnd = IR::SymOpnd::New(fieldSym, TyVar, m_func);
- IR::RegOpnd * regOpnd = this->BuildSrcOpnd((Js::RegSlot)regSlot);
- #if !FLOATVAR
- Js::OpCode opcode = Js::OpCode::StSlotBoxTemp;
- #else
- Js::OpCode opcode = Js::OpCode::StSlot;
- #endif
- IR::Instr * stSlotInstr = IR::Instr::New(opcode, fieldSymOpnd, regOpnd, m_func);
- if (offset != Js::Constants::NoByteCodeOffset)
- {
- this->AddInstr(stSlotInstr, offset);
- return nullptr;
- }
- else
- {
- return stSlotInstr;
- }
- }
- IR::Instr *
- IRBuilder::CreateLoopBodyReturnIPInstr(uint targetOffset, uint offset)
- {
- IR::RegOpnd * retOpnd = IR::RegOpnd::New(m_loopBodyRetIPSym, TyMachReg, m_func);
- IR::IntConstOpnd * exitOffsetOpnd = IR::IntConstOpnd::New(targetOffset, TyMachReg, m_func);
- return IR::Instr::New(Js::OpCode::Ld_I4, retOpnd, exitOffsetOpnd, m_func);
- }
- IR::Opnd *
- IRBuilder::InsertLoopBodyReturnIPInstr(uint targetOffset, uint offset)
- {
- IR::Instr * setRetValueInstr = CreateLoopBodyReturnIPInstr(targetOffset, offset);
- this->AddInstr(setRetValueInstr, offset);
- return setRetValueInstr->GetDst();
- }
- void
- IRBuilder::InsertDoneLoopBodyLoopCounter(uint32 lastOffset)
- {
- if (m_loopCounterSym == nullptr)
- {
- return;
- }
- IR::Instr * loopCounterStoreInstr = IR::Instr::New(Js::OpCode::StLoopBodyCount, m_func);
- IR::RegOpnd *countRegOpnd = IR::RegOpnd::New(m_loopCounterSym, TyInt32, this->m_func);
- countRegOpnd->SetIsJITOptimizedReg(true);
- loopCounterStoreInstr->SetSrc1(countRegOpnd);
- this->AddInstr(loopCounterStoreInstr, lastOffset + 1);
- return;
- }
- void
- IRBuilder::InsertIncrLoopBodyLoopCounter(IR::LabelInstr *loopTopLabelInstr)
- {
- Assert(this->IsLoopBody());
- IR::RegOpnd *loopCounterOpnd = IR::RegOpnd::New(m_loopCounterSym, TyInt32, this->m_func);
- IR::Instr * incr = IR::Instr::New(Js::OpCode::IncrLoopBodyCount, loopCounterOpnd, loopCounterOpnd, this->m_func);
- loopCounterOpnd->SetIsJITOptimizedReg(true);
- IR::Instr* nextRealInstr = loopTopLabelInstr->GetNextRealInstr();
- InsertInstr(incr, nextRealInstr);
- }
- void
- IRBuilder::InsertInitLoopBodyLoopCounter(uint loopNum)
- {
- Assert(this->IsLoopBody());
- intptr_t loopHeader = m_func->GetJITFunctionBody()->GetLoopHeaderAddr(loopNum);
- Assert(m_func->GetWorkItem()->GetLoopHeaderAddr() == loopHeader); //Init only once
- m_loopCounterSym = StackSym::New(TyVar, this->m_func);
- IR::RegOpnd* loopCounterOpnd = IR::RegOpnd::New(m_loopCounterSym, TyVar, this->m_func);
- loopCounterOpnd->SetIsJITOptimizedReg(true);
- IR::Instr * initInstr = IR::Instr::New(Js::OpCode::InitLoopBodyCount, loopCounterOpnd, this->m_func);
- m_lastInstr->InsertAfter(initInstr);
- m_lastInstr = initInstr;
- initInstr->SetByteCodeOffset(m_jnReader.GetCurrentOffset());
- }
- IR::AddrOpnd *
- IRBuilder::BuildAuxArrayOpnd(AuxArrayValue auxArrayType, uint32 auxArrayOffset)
- {
- switch (auxArrayType)
- {
- case AuxArrayValue::AuxPropertyIdArray:
- case AuxArrayValue::AuxIntArray:
- case AuxArrayValue::AuxFloatArray:
- case AuxArrayValue::AuxVarsArray:
- case AuxArrayValue::AuxFuncInfoArray:
- case AuxArrayValue::AuxVarArrayVarCount:
- {
- IR::AddrOpnd * opnd = IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetAuxDataAddr(auxArrayOffset), IR::AddrOpndKindDynamicAuxBufferRef, m_func);
- opnd->m_metadata = m_func->GetJITFunctionBody()->ReadFromAuxData(auxArrayOffset);
- return opnd;
- }
- default:
- Assert(UNREACHED);
- return nullptr;
- }
- }
- IR::Opnd *
- IRBuilder::BuildAuxObjectLiteralTypeRefOpnd(int objectId)
- {
- return IR::AddrOpnd::New(m_func->GetJITFunctionBody()->GetObjectLiteralTypeRef(objectId), IR::AddrOpndKindDynamicMisc, this->m_func);
- }
- void
- IRBuilder::DoClosureRegCheck(Js::RegSlot reg)
- {
- if (reg == Js::Constants::NoRegister)
- {
- return;
- }
- if (reg == m_func->GetJITFunctionBody()->GetEnvReg() ||
- reg == m_func->GetJITFunctionBody()->GetLocalClosureReg() ||
- reg == m_func->GetJITFunctionBody()->GetLocalFrameDisplayReg() ||
- reg == m_func->GetJITFunctionBody()->GetParamClosureReg())
- {
- Js::Throw::FatalInternalError();
- }
- }
- Js::RegSlot
- IRBuilder::InnerScopeIndexToRegSlot(uint32 index) const
- {
- if (index >= m_func->GetJITFunctionBody()->GetInnerScopeCount())
- {
- Js::Throw::FatalInternalError();
- }
- Js::RegSlot reg = m_func->GetJITFunctionBody()->GetFirstInnerScopeReg() + index;
- if (reg >= m_func->GetJITFunctionBody()->GetLocalsCount())
- {
- Js::Throw::FatalInternalError();
- }
- return reg;
- }
- bool
- IRBuilder::DoLoadInstructionArrayProfileInfo()
- {
- return !(!this->m_func->HasProfileInfo() ||
- (
- PHASE_OFF(Js::TypedArrayPhase, this->m_func->GetTopFunc()) &&
- PHASE_OFF(Js::ArrayCheckHoistPhase, this->m_func)
- ));
- }
- bool
- IRBuilder::AllowNativeArrayProfileInfo()
- {
- return !((!(m_func->GetTopFunc()->HasTry() && !m_func->GetTopFunc()->DoOptimizeTry()) && m_func->GetWeakFuncRef() && !m_func->HasArrayInfo()) ||
- m_func->IsJitInDebugMode());
- }
|