| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717 |
- //-------------------------------------------------------------------------------------------------------
- // 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);
- }
- }
- }
- }
- 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;
- }
- case Js::OpCode::InitConst:
- // Don't use InitConst in the JIT, as some dataflow tracking is missing, and we don't currently optimize for it.
- newOpcode = Js::OpCode::Ld_A;
- break;
- }
- 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());
- }
|