FunctionBody.cpp 368 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855785678577858785978607861786278637864786578667867786878697870787178727873787478757876787778787879788078817882788378847885788678877888788978907891789278937894789578967897789878997900790179027903790479057906790779087909791079117912791379147915791679177918791979207921792279237924792579267927792879297930793179327933793479357936793779387939794079417942794379447945794679477948794979507951795279537954795579567957795879597960796179627963796479657966796779687969797079717972797379747975797679777978797979807981798279837984798579867987798879897990799179927993799479957996799779987999800080018002800380048005800680078008800980108011801280138014801580168017801880198020802180228023802480258026802780288029803080318032803380348035803680378038803980408041804280438044804580468047804880498050805180528053805480558056805780588059806080618062806380648065806680678068806980708071807280738074807580768077807880798080808180828083808480858086808780888089809080918092809380948095809680978098809981008101810281038104810581068107810881098110811181128113811481158116811781188119812081218122812381248125812681278128812981308131813281338134813581368137813881398140814181428143814481458146814781488149815081518152815381548155815681578158815981608161816281638164816581668167816881698170817181728173817481758176817781788179818081818182818381848185818681878188818981908191819281938194819581968197819881998200820182028203820482058206820782088209821082118212821382148215821682178218821982208221822282238224822582268227822882298230823182328233823482358236823782388239824082418242824382448245824682478248824982508251825282538254825582568257825882598260826182628263826482658266826782688269827082718272827382748275827682778278827982808281828282838284828582868287828882898290829182928293829482958296829782988299830083018302830383048305830683078308830983108311831283138314831583168317831883198320832183228323832483258326832783288329833083318332833383348335833683378338833983408341834283438344834583468347834883498350835183528353835483558356835783588359836083618362836383648365836683678368836983708371837283738374837583768377837883798380838183828383838483858386838783888389839083918392839383948395839683978398839984008401840284038404840584068407840884098410841184128413841484158416841784188419842084218422842384248425842684278428842984308431843284338434843584368437843884398440844184428443844484458446844784488449845084518452845384548455845684578458845984608461846284638464846584668467846884698470847184728473847484758476847784788479848084818482848384848485848684878488848984908491849284938494849584968497849884998500850185028503850485058506850785088509851085118512851385148515851685178518851985208521852285238524852585268527852885298530853185328533853485358536853785388539854085418542854385448545854685478548854985508551855285538554855585568557855885598560856185628563856485658566856785688569857085718572857385748575857685778578857985808581858285838584858585868587858885898590859185928593859485958596859785988599860086018602860386048605860686078608860986108611861286138614861586168617861886198620862186228623862486258626862786288629863086318632863386348635863686378638863986408641864286438644864586468647864886498650865186528653865486558656865786588659866086618662866386648665866686678668866986708671867286738674867586768677867886798680868186828683868486858686868786888689869086918692869386948695869686978698869987008701870287038704870587068707870887098710871187128713871487158716871787188719872087218722872387248725872687278728872987308731873287338734873587368737873887398740874187428743874487458746874787488749875087518752875387548755875687578758875987608761876287638764876587668767876887698770877187728773877487758776877787788779878087818782878387848785878687878788878987908791879287938794879587968797879887998800880188028803880488058806880788088809881088118812881388148815881688178818881988208821882288238824882588268827882888298830883188328833883488358836883788388839884088418842884388448845884688478848884988508851885288538854885588568857885888598860886188628863886488658866886788688869887088718872887388748875887688778878887988808881888288838884888588868887888888898890889188928893889488958896889788988899890089018902890389048905890689078908890989108911891289138914891589168917891889198920892189228923892489258926892789288929893089318932893389348935893689378938893989408941894289438944894589468947894889498950895189528953895489558956895789588959896089618962896389648965896689678968896989708971897289738974897589768977897889798980898189828983898489858986898789888989899089918992899389948995899689978998899990009001900290039004900590069007900890099010901190129013901490159016901790189019902090219022902390249025902690279028902990309031903290339034903590369037903890399040904190429043904490459046904790489049905090519052905390549055905690579058905990609061906290639064906590669067906890699070907190729073907490759076907790789079908090819082908390849085908690879088908990909091909290939094909590969097909890999100910191029103910491059106910791089109911091119112911391149115911691179118911991209121912291239124912591269127912891299130913191329133913491359136913791389139914091419142914391449145914691479148914991509151915291539154915591569157915891599160916191629163916491659166916791689169917091719172917391749175917691779178917991809181918291839184918591869187918891899190919191929193919491959196919791989199920092019202920392049205920692079208920992109211921292139214921592169217921892199220922192229223922492259226922792289229923092319232923392349235923692379238923992409241924292439244924592469247924892499250925192529253925492559256925792589259926092619262926392649265926692679268926992709271927292739274927592769277927892799280928192829283928492859286928792889289929092919292929392949295929692979298929993009301930293039304930593069307930893099310931193129313931493159316931793189319932093219322932393249325932693279328932993309331933293339334933593369337933893399340934193429343934493459346934793489349935093519352935393549355935693579358935993609361936293639364936593669367936893699370937193729373937493759376937793789379938093819382938393849385938693879388938993909391939293939394939593969397939893999400940194029403940494059406940794089409941094119412941394149415941694179418941994209421942294239424942594269427942894299430943194329433943494359436943794389439944094419442944394449445944694479448944994509451945294539454945594569457945894599460946194629463946494659466946794689469947094719472947394749475947694779478947994809481948294839484948594869487948894899490949194929493949494959496949794989499950095019502950395049505950695079508950995109511951295139514951595169517951895199520952195229523952495259526952795289529953095319532953395349535953695379538953995409541954295439544954595469547954895499550955195529553955495559556955795589559956095619562956395649565956695679568956995709571957295739574957595769577957895799580958195829583958495859586958795889589959095919592959395949595959695979598959996009601960296039604960596069607960896099610961196129613961496159616961796189619962096219622962396249625962696279628962996309631963296339634963596369637963896399640964196429643964496459646964796489649965096519652965396549655965696579658965996609661966296639664966596669667966896699670967196729673967496759676967796789679968096819682968396849685968696879688968996909691969296939694969596969697969896999700970197029703970497059706970797089709971097119712971397149715971697179718971997209721972297239724972597269727972897299730973197329733973497359736973797389739974097419742974397449745974697479748974997509751975297539754975597569757975897599760976197629763976497659766976797689769977097719772977397749775
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeBasePch.h"
  6. #include "ByteCode/ByteCodeApi.h"
  7. #include "ByteCode/ByteCodeDumper.h"
  8. #include "Language/AsmJsTypes.h"
  9. #include "Language/AsmJsModule.h"
  10. #include "ByteCode/ByteCodeSerializer.h"
  11. #include "Language/FunctionCodeGenRuntimeData.h"
  12. #include "ByteCode/ScopeInfo.h"
  13. #include "Base/EtwTrace.h"
  14. #ifdef VTUNE_PROFILING
  15. #include "Base/VTuneChakraProfile.h"
  16. #endif
  17. #ifdef DYNAMIC_PROFILE_MUTATOR
  18. #include "Language/DynamicProfileMutator.h"
  19. #endif
  20. #include "Language/SourceDynamicProfileManager.h"
  21. #ifdef ENABLE_SCRIPT_DEBUGGING
  22. #include "Debug/ProbeContainer.h"
  23. #include "Debug/DebugContext.h"
  24. #endif
  25. #include "Parser.h"
  26. #include "RegexCommon.h"
  27. #include "RegexPattern.h"
  28. #include "Library/RegexHelper.h"
  29. #include "Language/InterpreterStackFrame.h"
  30. #include "Library/ModuleRoot.h"
  31. #include "Types/PathTypeHandler.h"
  32. #include "Common/MathUtil.h"
  33. #if ENABLE_NATIVE_CODEGEN
  34. #include "NativeEntryPointData.h"
  35. #include "JitTransferData.h"
  36. #endif
  37. namespace Js
  38. {
  39. // The VS2013 linker treats this as a redefinition of an already
  40. // defined constant and complains. So skip the declaration if we're compiling
  41. // with VS2013 or below.
  42. #if !defined(_MSC_VER) || _MSC_VER >= 1900
  43. uint const ScopeSlots::MaxEncodedSlotCount;
  44. #endif
  45. #ifdef FIELD_ACCESS_STATS
  46. void FieldAccessStats::Add(FieldAccessStats* other)
  47. {
  48. Assert(other != nullptr);
  49. this->totalInlineCacheCount += other->totalInlineCacheCount;
  50. this->noInfoInlineCacheCount += other->noInfoInlineCacheCount;
  51. this->monoInlineCacheCount += other->monoInlineCacheCount;
  52. this->emptyMonoInlineCacheCount += other->emptyMonoInlineCacheCount;
  53. this->polyInlineCacheCount += other->polyInlineCacheCount;
  54. this->nullPolyInlineCacheCount += other->nullPolyInlineCacheCount;
  55. this->emptyPolyInlineCacheCount += other->emptyPolyInlineCacheCount;
  56. this->ignoredPolyInlineCacheCount += other->ignoredPolyInlineCacheCount;
  57. this->highUtilPolyInlineCacheCount += other->highUtilPolyInlineCacheCount;
  58. this->lowUtilPolyInlineCacheCount += other->lowUtilPolyInlineCacheCount;
  59. this->equivPolyInlineCacheCount += other->equivPolyInlineCacheCount;
  60. this->nonEquivPolyInlineCacheCount += other->nonEquivPolyInlineCacheCount;
  61. this->disabledPolyInlineCacheCount += other->disabledPolyInlineCacheCount;
  62. this->clonedMonoInlineCacheCount += other->clonedMonoInlineCacheCount;
  63. this->clonedPolyInlineCacheCount += other->clonedPolyInlineCacheCount;
  64. }
  65. #endif
  66. // FunctionProxy methods
  67. FunctionProxy::FunctionProxy(ScriptContext* scriptContext, Utf8SourceInfo* utf8SourceInfo, uint functionNumber):
  68. m_isTopLevel(false),
  69. m_isPublicLibraryCode(false),
  70. m_scriptContext(scriptContext),
  71. deferredPrototypeType(nullptr),
  72. undeferredFunctionType(nullptr),
  73. m_utf8SourceInfo(utf8SourceInfo),
  74. m_functionNumber(functionNumber),
  75. m_defaultEntryPointInfo(nullptr),
  76. m_displayNameIsRecyclerAllocated(false),
  77. m_tag11(true),
  78. m_isJsBuiltInCode(false)
  79. {
  80. PERF_COUNTER_INC(Code, TotalFunction);
  81. }
  82. bool FunctionProxy::IsWasmFunction() const
  83. {
  84. return GetFunctionInfo()->HasParseableInfo() &&
  85. GetFunctionInfo()->GetFunctionBody()->IsWasmFunction();
  86. }
  87. Recycler* FunctionProxy::GetRecycler() const
  88. {
  89. return m_scriptContext->GetRecycler();
  90. }
  91. void* FunctionProxy::GetAuxPtr(AuxPointerType e) const
  92. {
  93. if (this->auxPtrs == nullptr)
  94. {
  95. return nullptr;
  96. }
  97. // On process detach this can be called from another thread but the ThreadContext should be locked
  98. Assert(ThreadContext::GetContextForCurrentThread() || ThreadContext::GetCriticalSection()->IsLocked());
  99. return AuxPtrsT::GetAuxPtr(this, e);
  100. }
  101. void* FunctionProxy::GetAuxPtrWithLock(AuxPointerType e) const
  102. {
  103. if (this->auxPtrs == nullptr)
  104. {
  105. return nullptr;
  106. }
  107. #if DBG && ENABLE_NATIVE_CODEGEN && defined(_WIN32)
  108. // the lock for work item queue should not be locked while accessing AuxPtrs in background thread
  109. auto jobProcessor = this->GetScriptContext()->GetThreadContext()->GetJobProcessor();
  110. auto jobProcessorCS = jobProcessor->GetCriticalSection();
  111. // ->IsLocked is not supported on xplat
  112. Assert(!jobProcessorCS || !jobProcessor->ProcessesInBackground() || !jobProcessorCS->IsLocked());
  113. #endif
  114. AutoCriticalSection autoCS(this->GetScriptContext()->GetThreadContext()->GetFunctionBodyLock());
  115. return AuxPtrsT::GetAuxPtr(this, e);
  116. }
  117. void FunctionProxy::SetAuxPtr(AuxPointerType e, void* ptr)
  118. {
  119. // On process detach this can be called from another thread but the ThreadContext should be locked
  120. Assert(ThreadContext::GetContextForCurrentThread() || ThreadContext::GetCriticalSection()->IsLocked());
  121. if (ptr == nullptr && GetAuxPtr(e) == nullptr)
  122. {
  123. return;
  124. }
  125. // when setting ptr to null we never need to promote
  126. AutoCriticalSection autoCS(this->GetScriptContext()->GetThreadContext()->GetFunctionBodyLock());
  127. AuxPtrsT::SetAuxPtr(this, e, ptr);
  128. }
  129. uint FunctionProxy::GetSourceContextId() const
  130. {
  131. return this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId;
  132. }
  133. char16* FunctionProxy::GetDebugNumberSet(wchar(&bufferToWriteTo)[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]) const
  134. {
  135. // (#%u.%u), #%u --> (source file Id . function Id) , function Number
  136. int len = swprintf_s(bufferToWriteTo, MAX_FUNCTION_BODY_DEBUG_STRING_SIZE, _u(" (#%d.%u), #%u"),
  137. (int)this->GetSourceContextId(), this->GetLocalFunctionId(), this->GetFunctionNumber());
  138. Assert(len > 8);
  139. return bufferToWriteTo;
  140. }
  141. bool
  142. FunctionProxy::IsFunctionBody() const
  143. {
  144. return !IsDeferredDeserializeFunction() && GetParseableFunctionInfo()->IsFunctionParsed();
  145. }
  146. uint
  147. ParseableFunctionInfo::GetSourceIndex() const
  148. {
  149. return this->m_sourceIndex;
  150. }
  151. LPCUTF8
  152. ParseableFunctionInfo::GetSource(const char16* reason) const
  153. {
  154. return this->GetUtf8SourceInfo()->GetSource(reason == nullptr ? _u("ParseableFunctionInfo::GetSource") : reason) + this->StartOffset();
  155. }
  156. LPCUTF8
  157. ParseableFunctionInfo::GetToStringSource(const char16* reason) const
  158. {
  159. return this->GetUtf8SourceInfo()->GetSource(reason == nullptr ? _u("ParseableFunctionInfo::GetToStringSource") : reason) + this->PrintableStartOffset();
  160. }
  161. LPCUTF8
  162. ParseableFunctionInfo::GetStartOfDocument(const char16* reason) const
  163. {
  164. return this->GetUtf8SourceInfo()->GetSource(reason == nullptr ? _u("ParseableFunctionInfo::GetStartOfDocument") : reason);
  165. }
  166. bool
  167. ParseableFunctionInfo::IsDynamicFunction() const
  168. {
  169. return this->m_isDynamicFunction;
  170. }
  171. bool
  172. ParseableFunctionInfo::IsDynamicScript() const
  173. {
  174. return this->GetSourceContextInfo()->IsDynamic();
  175. }
  176. charcount_t
  177. ParseableFunctionInfo::StartInDocument() const
  178. {
  179. return this->m_cchStartOffset;
  180. }
  181. uint
  182. ParseableFunctionInfo::StartOffset() const
  183. {
  184. return this->m_cbStartOffset;
  185. }
  186. uint
  187. ParseableFunctionInfo::PrintableStartOffset() const
  188. {
  189. return this->m_cbStartPrintOffset;
  190. }
  191. void ParseableFunctionInfo::RegisterFuncToDiag(ScriptContext * scriptContext, char16 const * pszTitle)
  192. {
  193. #ifdef ENABLE_SCRIPT_DEBUGGING
  194. // Register the function to the PDM as eval code (the debugger app will show file as 'eval code')
  195. scriptContext->GetDebugContext()->RegisterFunction(this, pszTitle);
  196. #endif
  197. }
  198. bool ParseableFunctionInfo::IsES6ModuleCode() const
  199. {
  200. return (GetGrfscr() & fscrIsModuleCode) == fscrIsModuleCode;
  201. }
  202. // Given an offset into the source buffer, determine if the end of this SourceInfo
  203. // lies after the given offset.
  204. bool
  205. ParseableFunctionInfo::EndsAfter(size_t offset) const
  206. {
  207. return offset < this->StartOffset() + this->LengthInBytes();
  208. }
  209. uint32 FunctionBody::GetCountField(FunctionBody::CounterFields fieldEnum) const
  210. {
  211. #if DBG
  212. bool isCountersLockedDown = counters.isLockedDown;
  213. Assert(ThreadContext::GetContextForCurrentThread() || isCountersLockedDown
  214. || (ThreadContext::GetCriticalSection()->IsLocked() && this->m_scriptContext->GetThreadContext()->GetFunctionBodyLock()->IsLocked())); // etw rundown
  215. #endif
  216. return counters.Get(fieldEnum);
  217. }
  218. uint32 FunctionBody::SetCountField(FunctionBody::CounterFields fieldEnum, uint32 val)
  219. {
  220. DebugOnly(bool isCountersLockedDown = counters.isLockedDown);
  221. Assert(!isCountersLockedDown || counters.isClosing);
  222. return counters.Set(fieldEnum, val, this);
  223. }
  224. uint32 FunctionBody::IncreaseCountField(FunctionBody::CounterFields fieldEnum)
  225. {
  226. DebugOnly(bool isCountersLockedDown = counters.isLockedDown);
  227. Assert(!isCountersLockedDown || counters.isClosing);
  228. return counters.Increase(fieldEnum, this);
  229. }
  230. void
  231. FunctionBody::RecordStatementMap(StatementMap* pStatementMap)
  232. {
  233. Assert(!this->m_sourceInfo.pSpanSequence);
  234. Recycler* recycler = this->m_scriptContext->GetRecycler();
  235. StatementMapList * statementMaps = this->GetStatementMaps();
  236. if (!statementMaps)
  237. {
  238. statementMaps = RecyclerNew(recycler, StatementMapList, recycler);
  239. this->SetStatementMaps(statementMaps);
  240. }
  241. statementMaps->Add(pStatementMap);
  242. }
  243. void
  244. FunctionBody::RecordStatementMap(SmallSpanSequenceIter &iter, StatementData * data)
  245. {
  246. Assert(!this->GetStatementMaps());
  247. if (!this->m_sourceInfo.pSpanSequence)
  248. {
  249. this->m_sourceInfo.pSpanSequence = HeapNew(SmallSpanSequence);
  250. }
  251. this->m_sourceInfo.pSpanSequence->RecordARange(iter, data);
  252. }
  253. void
  254. FunctionBody::RecordStatementAdjustment(uint offset, StatementAdjustmentType adjType)
  255. {
  256. this->EnsureAuxStatementData();
  257. Recycler* recycler = this->m_scriptContext->GetRecycler();
  258. if (this->GetStatementAdjustmentRecords() == nullptr)
  259. {
  260. m_sourceInfo.m_auxStatementData->m_statementAdjustmentRecords = RecyclerNew(recycler, StatementAdjustmentRecordList, recycler);
  261. }
  262. StatementAdjustmentRecord record(adjType, offset);
  263. this->GetStatementAdjustmentRecords()->Add(record); // Will copy stack value and put the copy into the container.
  264. }
  265. BOOL
  266. FunctionBody::GetBranchOffsetWithin(uint start, uint end, StatementAdjustmentRecord* record)
  267. {
  268. Assert(start < end);
  269. if (!this->GetStatementAdjustmentRecords())
  270. {
  271. // No Offset
  272. return FALSE;
  273. }
  274. int count = this->GetStatementAdjustmentRecords()->Count();
  275. for (int i = 0; i < count; i++)
  276. {
  277. StatementAdjustmentRecord item = this->GetStatementAdjustmentRecords()->Item(i);
  278. if (item.GetByteCodeOffset() > start && item.GetByteCodeOffset() < end)
  279. {
  280. *record = item;
  281. return TRUE;
  282. }
  283. }
  284. // No offset found in the range.
  285. return FALSE;
  286. }
  287. bool
  288. FunctionBody::SkipAutoProfileForCoroutine() const
  289. {
  290. return this->IsCoroutine() && CONFIG_ISENABLED(Js::JitES6GeneratorsFlag);
  291. }
  292. bool
  293. FunctionBody::IsGeneratorAndJitIsDisabled() const
  294. {
  295. return this->IsCoroutine() && !(CONFIG_ISENABLED(Js::JitES6GeneratorsFlag) && !this->GetHasTry() && !this->IsInDebugMode() && !this->IsAsync());
  296. }
  297. ScriptContext* EntryPointInfo::GetScriptContext()
  298. {
  299. Assert(!IsCleanedUp());
  300. return this->library->GetScriptContext();
  301. }
  302. #if ENABLE_NATIVE_CODEGEN
  303. #if DBG_DUMP | defined(VTUNE_PROFILING)
  304. void
  305. EntryPointInfo::RecordNativeMap(uint32 nativeOffset, uint32 statementIndex)
  306. {
  307. auto& nativeOffsetMaps = this->GetNativeEntryPointData()->GetNativeOffsetMaps();
  308. int count = nativeOffsetMaps.Count();
  309. if (count)
  310. {
  311. NativeEntryPointData::NativeOffsetMap* previous = &nativeOffsetMaps.Item(count-1);
  312. // Check if the range is still not finished.
  313. if (previous->nativeOffsetSpan.begin == previous->nativeOffsetSpan.end)
  314. {
  315. if (previous->statementIndex == statementIndex)
  316. {
  317. // If the statement index is the same, we can continue with the previous range
  318. return;
  319. }
  320. // If the range is empty, replace the previous range.
  321. if ((uint32)previous->nativeOffsetSpan.begin == nativeOffset)
  322. {
  323. if (statementIndex == Js::Constants::NoStatementIndex)
  324. {
  325. nativeOffsetMaps.RemoveAtEnd();
  326. }
  327. else
  328. {
  329. previous->statementIndex = statementIndex;
  330. }
  331. return;
  332. }
  333. // Close the previous range
  334. previous->nativeOffsetSpan.end = nativeOffset;
  335. }
  336. }
  337. if (statementIndex == Js::Constants::NoStatementIndex)
  338. {
  339. // We do not explicitly record the offsets that do not map to user code.
  340. return;
  341. }
  342. NativeEntryPointData::NativeOffsetMap map;
  343. map.statementIndex = statementIndex;
  344. map.nativeOffsetSpan.begin = nativeOffset;
  345. map.nativeOffsetSpan.end = nativeOffset;
  346. nativeOffsetMaps.Add(map);
  347. }
  348. #endif
  349. #endif
  350. void
  351. FunctionBody::CopySourceInfo(ParseableFunctionInfo* originalFunctionInfo)
  352. {
  353. this->FinishSourceInfo();
  354. }
  355. // When sourceInfo is complete, register this functionBody to utf8SourceInfo. This ensures we never
  356. // put incomplete functionBody into utf8SourceInfo map. (Previously we do it in FunctionBody constructor.
  357. // If an error occurs thereafter before SetSourceInfo, e.g. OOM, we'll have an incomplete functionBody
  358. // in utf8SourceInfo map whose source range is unknown and can't be reparsed.)
  359. void FunctionBody::FinishSourceInfo()
  360. {
  361. this->GetUtf8SourceInfo()->SetFunctionBody(this);
  362. }
  363. RegSlot FunctionBody::GetFrameDisplayRegister() const
  364. {
  365. return this->m_sourceInfo.frameDisplayRegister;
  366. }
  367. void FunctionBody::SetFrameDisplayRegister(RegSlot frameDisplayRegister)
  368. {
  369. this->m_sourceInfo.frameDisplayRegister = frameDisplayRegister;
  370. }
  371. RegSlot FunctionBody::GetObjectRegister() const
  372. {
  373. return this->m_sourceInfo.objectRegister;
  374. }
  375. void FunctionBody::SetObjectRegister(RegSlot objectRegister)
  376. {
  377. this->m_sourceInfo.objectRegister = objectRegister;
  378. }
  379. ScopeObjectChain *FunctionBody::GetScopeObjectChain() const
  380. {
  381. return this->m_sourceInfo.pScopeObjectChain;
  382. }
  383. void FunctionBody::SetScopeObjectChain(ScopeObjectChain *pScopeObjectChain)
  384. {
  385. this->m_sourceInfo.pScopeObjectChain = pScopeObjectChain;
  386. }
  387. ByteBlock *FunctionBody::GetProbeBackingBlock()
  388. {
  389. return this->m_sourceInfo.m_probeBackingBlock;
  390. }
  391. void FunctionBody::SetProbeBackingBlock(ByteBlock* probeBackingBlock)
  392. {
  393. this->m_sourceInfo.m_probeBackingBlock = probeBackingBlock;
  394. }
  395. FunctionBody * FunctionBody::NewFromRecycler(ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
  396. Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, FunctionInfo::Attributes attributes, FunctionBodyFlags flags
  397. #ifdef PERF_COUNTERS
  398. , bool isDeserializedFunction
  399. #endif
  400. )
  401. {
  402. return FunctionBody::NewFromRecycler(scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo,
  403. scriptContext->GetThreadContext()->NewFunctionNumber(), uScriptId, functionId, attributes, flags
  404. #ifdef PERF_COUNTERS
  405. , isDeserializedFunction
  406. #endif
  407. );
  408. }
  409. FunctionBody * FunctionBody::NewFromRecycler(ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
  410. Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, FunctionInfo::Attributes attributes, FunctionBodyFlags flags
  411. #ifdef PERF_COUNTERS
  412. , bool isDeserializedFunction
  413. #endif
  414. )
  415. {
  416. #ifdef PERF_COUNTERS
  417. return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(), FunctionBody, scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo, uFunctionNumber, uScriptId, functionId, attributes, flags, isDeserializedFunction);
  418. #else
  419. return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(), FunctionBody, scriptContext, displayName, displayNameLength, displayShortNameOffset, nestedCount, sourceInfo, uFunctionNumber, uScriptId, functionId, attributes, flags);
  420. #endif
  421. }
  422. FunctionBody *
  423. FunctionBody::NewFromParseableFunctionInfo(ParseableFunctionInfo * parseableFunctionInfo)
  424. {
  425. ScriptContext * scriptContext = parseableFunctionInfo->GetScriptContext();
  426. uint nestedCount = parseableFunctionInfo->GetNestedCount();
  427. FunctionBody * functionBody = RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(),
  428. FunctionBody,
  429. parseableFunctionInfo);
  430. // Initialize nested function array, update back pointers
  431. for (uint i = 0; i < nestedCount; i++)
  432. {
  433. FunctionInfo * nestedInfo = parseableFunctionInfo->GetNestedFunc(i);
  434. functionBody->SetNestedFunc(nestedInfo, i, 0);
  435. }
  436. return functionBody;
  437. }
  438. FunctionBody::FunctionBody(ScriptContext* scriptContext, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount,
  439. Utf8SourceInfo* utf8SourceInfo, uint uFunctionNumber, uint uScriptId,
  440. Js::LocalFunctionId functionId, FunctionInfo::Attributes attributes, FunctionBodyFlags flags
  441. #ifdef PERF_COUNTERS
  442. , bool isDeserializedFunction
  443. #endif
  444. ) :
  445. ParseableFunctionInfo(scriptContext->CurrentThunk, nestedCount, functionId, utf8SourceInfo, scriptContext, uFunctionNumber, displayName, displayNameLength, displayShortNameOffset, attributes, flags),
  446. counters(this),
  447. m_uScriptId(uScriptId),
  448. cleanedUp(false),
  449. sourceInfoCleanedUp(false),
  450. profiledLdLenCount(0),
  451. profiledLdElemCount(0),
  452. profiledStElemCount(0),
  453. profiledCallSiteCount(0),
  454. profiledArrayCallSiteCount(0),
  455. profiledDivOrRemCount(0),
  456. profiledSwitchCount(0),
  457. profiledReturnTypeCount(0),
  458. profiledSlotCount(0),
  459. m_isFuncRegistered(false),
  460. m_isFuncRegisteredToDiag(false),
  461. m_hasBailoutInstrInJittedCode(false),
  462. m_depth(0),
  463. inlineDepth(0),
  464. m_pendingLoopHeaderRelease(false),
  465. hasCachedScopePropIds(false),
  466. m_argUsedForBranch(0),
  467. m_envDepth((uint16)-1),
  468. loopInterpreterLimit(CONFIG_FLAG(LoopInterpretCount)),
  469. savedPolymorphicCacheState(0),
  470. debuggerScopeIndex(0),
  471. m_hasFinally(false),
  472. #if ENABLE_PROFILE_INFO
  473. dynamicProfileInfo(nullptr),
  474. #endif
  475. savedInlinerVersion(0),
  476. #if ENABLE_NATIVE_CODEGEN
  477. savedImplicitCallsFlags(ImplicitCall_HasNoInfo),
  478. #endif
  479. hasExecutionDynamicProfileInfo(false),
  480. m_hasAllNonLocalReferenced(false),
  481. m_hasSetIsObject(false),
  482. m_hasFunExprNameReference(false),
  483. m_CallsEval(false),
  484. m_ChildCallsEval(false),
  485. m_hasReferenceableBuiltInArguments(false),
  486. m_isParamAndBodyScopeMerged(true),
  487. m_firstFunctionObject(true),
  488. m_inlineCachesOnFunctionObject(false),
  489. m_hasDoneAllNonLocalReferenced(false),
  490. m_hasFunctionCompiledSent(false),
  491. byteCodeCache(nullptr),
  492. m_hasLocalClosureRegister(false),
  493. m_hasParamClosureRegister(false),
  494. m_hasLocalFrameDisplayRegister(false),
  495. m_hasEnvRegister(false),
  496. m_hasThisRegisterForEventHandler(false),
  497. m_hasFirstInnerScopeRegister(false),
  498. m_hasFuncExprScopeRegister(false),
  499. m_hasFirstTmpRegister(false),
  500. m_hasActiveReference(false),
  501. m_tag31(true),
  502. m_tag32(true),
  503. m_tag33(true),
  504. m_nativeEntryPointUsed(false),
  505. hasDoneLoopBodyCodeGen(false),
  506. bailOnMisingProfileCount(0),
  507. bailOnMisingProfileRejitCount(0),
  508. byteCodeBlock(nullptr),
  509. entryPoints(nullptr),
  510. m_constTable(nullptr),
  511. inlineCaches(nullptr),
  512. cacheIdToPropertyIdMap(nullptr),
  513. wasCalledFromLoop(false),
  514. hasScopeObject(false),
  515. hasNestedLoop(false),
  516. recentlyBailedOutOfJittedLoopBody(false),
  517. m_isAsmJsScheduledForFullJIT(false),
  518. m_asmJsTotalLoopCount(0)
  519. //
  520. // Even if the function does not require any locals, we must always have "R0" to propagate
  521. // a return value. By enabling this here, we avoid unnecessary conditionals during execution.
  522. //
  523. #ifdef IR_VIEWER
  524. ,m_isIRDumpEnabled(false)
  525. ,m_irDumpBaseObject(nullptr)
  526. #endif /* IR_VIEWER */
  527. , m_isFromNativeCodeModule(false)
  528. , hasHotLoop(false)
  529. , m_isPartialDeserializedFunction(false)
  530. #if DBG
  531. , m_isSerialized(false)
  532. #endif
  533. #ifdef PERF_COUNTERS
  534. , m_isDeserializedFunction(isDeserializedFunction)
  535. #endif
  536. #if DBG
  537. , m_DEBUG_executionCount(0)
  538. , m_nativeEntryPointIsInterpreterThunk(false)
  539. , m_canDoStackNestedFunc(false)
  540. , m_inlineCacheTypes(nullptr)
  541. , m_iProfileSession(-1)
  542. #endif
  543. #if ENABLE_DEBUG_CONFIG_OPTIONS
  544. , regAllocLoadCount(0)
  545. , regAllocStoreCount(0)
  546. , callCountStats(0)
  547. #endif
  548. {
  549. SetCountField(CounterFields::ConstantCount, 1);
  550. this->SetDefaultFunctionEntryPointInfo((FunctionEntryPointInfo*) this->GetDefaultEntryPointInfo(), DefaultEntryThunk);
  551. this->m_hasBeenParsed = true;
  552. #ifdef PERF_COUNTERS
  553. if (isDeserializedFunction)
  554. {
  555. PERF_COUNTER_INC(Code, DeserializedFunctionBody);
  556. }
  557. #endif
  558. Assert(!utf8SourceInfo || m_uScriptId == utf8SourceInfo->GetSrcInfo()->sourceContextInfo->sourceContextId);
  559. // Sync entryPoints changes to etw rundown lock
  560. CriticalSection* syncObj = scriptContext->GetThreadContext()->GetFunctionBodyLock();
  561. this->entryPoints = RecyclerNew(this->m_scriptContext->GetRecycler(), FunctionEntryPointList, this->m_scriptContext->GetRecycler(), syncObj);
  562. this->AddEntryPointToEntryPointList(this->GetDefaultFunctionEntryPointInfo());
  563. Assert(this->GetDefaultEntryPointInfo()->jsMethod != nullptr);
  564. InitDisableInlineApply();
  565. InitDisableInlineSpread();
  566. }
  567. FunctionBody::FunctionBody(ParseableFunctionInfo * proxy) :
  568. ParseableFunctionInfo(proxy),
  569. counters(this),
  570. m_uScriptId(proxy->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId),
  571. cleanedUp(false),
  572. sourceInfoCleanedUp(false),
  573. profiledLdLenCount(0),
  574. profiledLdElemCount(0),
  575. profiledStElemCount(0),
  576. profiledCallSiteCount(0),
  577. profiledArrayCallSiteCount(0),
  578. profiledDivOrRemCount(0),
  579. profiledSwitchCount(0),
  580. profiledReturnTypeCount(0),
  581. profiledSlotCount(0),
  582. m_isFuncRegistered(false),
  583. m_isFuncRegisteredToDiag(false),
  584. m_hasBailoutInstrInJittedCode(false),
  585. m_depth(0),
  586. inlineDepth(0),
  587. m_pendingLoopHeaderRelease(false),
  588. hasCachedScopePropIds(false),
  589. m_argUsedForBranch(0),
  590. m_envDepth((uint16)-1),
  591. loopInterpreterLimit(CONFIG_FLAG(LoopInterpretCount)),
  592. savedPolymorphicCacheState(0),
  593. debuggerScopeIndex(0),
  594. m_hasFinally(false),
  595. #if ENABLE_PROFILE_INFO
  596. dynamicProfileInfo(nullptr),
  597. #endif
  598. savedInlinerVersion(0),
  599. #if ENABLE_NATIVE_CODEGEN
  600. savedImplicitCallsFlags(ImplicitCall_HasNoInfo),
  601. #endif
  602. hasExecutionDynamicProfileInfo(false),
  603. m_hasAllNonLocalReferenced(false),
  604. m_hasSetIsObject(false),
  605. m_hasFunExprNameReference(false),
  606. m_CallsEval(false),
  607. m_ChildCallsEval(false),
  608. m_hasReferenceableBuiltInArguments(false),
  609. m_isParamAndBodyScopeMerged(true),
  610. m_firstFunctionObject(true),
  611. m_inlineCachesOnFunctionObject(false),
  612. m_hasDoneAllNonLocalReferenced(false),
  613. m_hasFunctionCompiledSent(false),
  614. byteCodeCache(nullptr),
  615. m_hasLocalClosureRegister(false),
  616. m_hasParamClosureRegister(false),
  617. m_hasLocalFrameDisplayRegister(false),
  618. m_hasEnvRegister(false),
  619. m_hasThisRegisterForEventHandler(false),
  620. m_hasFirstInnerScopeRegister(false),
  621. m_hasFuncExprScopeRegister(false),
  622. m_hasFirstTmpRegister(false),
  623. m_hasActiveReference(false),
  624. m_tag31(true),
  625. m_tag32(true),
  626. m_tag33(true),
  627. m_nativeEntryPointUsed(false),
  628. hasDoneLoopBodyCodeGen(false),
  629. bailOnMisingProfileCount(0),
  630. bailOnMisingProfileRejitCount(0),
  631. byteCodeBlock(nullptr),
  632. entryPoints(nullptr),
  633. m_constTable(nullptr),
  634. inlineCaches(nullptr),
  635. cacheIdToPropertyIdMap(nullptr),
  636. wasCalledFromLoop(false),
  637. hasScopeObject(false),
  638. hasNestedLoop(false),
  639. recentlyBailedOutOfJittedLoopBody(false),
  640. m_isAsmJsScheduledForFullJIT(false),
  641. m_asmJsTotalLoopCount(0)
  642. //
  643. // Even if the function does not require any locals, we must always have "R0" to propagate
  644. // a return value. By enabling this here, we avoid unnecessary conditionals during execution.
  645. //
  646. #ifdef IR_VIEWER
  647. ,m_isIRDumpEnabled(false)
  648. ,m_irDumpBaseObject(nullptr)
  649. #endif /* IR_VIEWER */
  650. , m_isFromNativeCodeModule(false)
  651. , hasHotLoop(false)
  652. , m_isPartialDeserializedFunction(false)
  653. #if DBG
  654. , m_isSerialized(false)
  655. #endif
  656. #ifdef PERF_COUNTERS
  657. , m_isDeserializedFunction(false)
  658. #endif
  659. #if DBG
  660. , m_DEBUG_executionCount(0)
  661. , m_nativeEntryPointIsInterpreterThunk(false)
  662. , m_canDoStackNestedFunc(false)
  663. , m_inlineCacheTypes(nullptr)
  664. , m_iProfileSession(-1)
  665. #endif
  666. #if ENABLE_DEBUG_CONFIG_OPTIONS
  667. , regAllocLoadCount(0)
  668. , regAllocStoreCount(0)
  669. , callCountStats(0)
  670. #endif
  671. {
  672. ScriptContext * scriptContext = proxy->GetScriptContext();
  673. SetCountField(CounterFields::ConstantCount, 1);
  674. proxy->UpdateFunctionBodyImpl(this);
  675. this->m_defaultEntryPointInfo = RecyclerNewFinalized(scriptContext->GetRecycler(),
  676. FunctionEntryPointInfo, this, scriptContext->CurrentThunk, scriptContext->GetThreadContext());
  677. this->SetDefaultFunctionEntryPointInfo((FunctionEntryPointInfo*) this->GetDefaultEntryPointInfo(), DefaultEntryThunk);
  678. this->m_hasBeenParsed = true;
  679. Assert(!proxy->GetUtf8SourceInfo() || m_uScriptId == proxy->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId);
  680. // Sync entryPoints changes to etw rundown lock
  681. CriticalSection* syncObj = scriptContext->GetThreadContext()->GetFunctionBodyLock();
  682. this->entryPoints = RecyclerNew(scriptContext->GetRecycler(), FunctionEntryPointList, scriptContext->GetRecycler(), syncObj);
  683. this->AddEntryPointToEntryPointList(this->GetDefaultFunctionEntryPointInfo());
  684. Assert(this->GetDefaultEntryPointInfo()->jsMethod != nullptr);
  685. InitDisableInlineApply();
  686. InitDisableInlineSpread();
  687. }
  688. bool FunctionBody::InterpretedSinceCallCountCollection() const
  689. {
  690. return executionState.InterpretedSinceCallCountCollection();
  691. }
  692. void FunctionBody::CollectInterpretedCounts()
  693. {
  694. executionState.CollectInterpretedCounts();
  695. }
  696. void FunctionBody::IncrInactiveCount(uint increment)
  697. {
  698. this->inactiveCount = UInt32Math::Add(this->inactiveCount, increment);
  699. }
  700. bool FunctionBody::IsActiveFunction(ActiveFunctionSet * pActiveFuncs) const
  701. {
  702. return !!pActiveFuncs->Test(this->GetFunctionNumber());
  703. }
  704. bool FunctionBody::TestAndUpdateActiveFunctions(ActiveFunctionSet * pActiveFuncs) const
  705. {
  706. return !!pActiveFuncs->TestAndSet(this->GetFunctionNumber());
  707. }
  708. void FunctionBody::UpdateActiveFunctionsForOneDataSet(ActiveFunctionSet *pActiveFuncs, FunctionCodeGenRuntimeData *parentData, Field(FunctionCodeGenRuntimeData*)* dataSet, uint count) const
  709. {
  710. FunctionCodeGenRuntimeData *inlineeData;
  711. for (uint i = 0; i < count; i++)
  712. {
  713. for (inlineeData = dataSet[i]; inlineeData; inlineeData = inlineeData->GetNext())
  714. {
  715. // inlineeData == parentData indicates a cycle in the structure. We've already processed parentData, so don't descend.
  716. if (inlineeData != parentData)
  717. {
  718. inlineeData->GetFunctionBody()->UpdateActiveFunctionSet(pActiveFuncs, inlineeData);
  719. }
  720. }
  721. }
  722. }
  723. void FunctionBody::UpdateActiveFunctionSet(ActiveFunctionSet *pActiveFuncs, FunctionCodeGenRuntimeData *callSiteData) const
  724. {
  725. // Always walk the inlinee and ldFldInlinee data (if we have them), as they are different at each call site.
  726. if (callSiteData)
  727. {
  728. if (callSiteData->GetInlinees())
  729. {
  730. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, callSiteData, callSiteData->GetInlinees(), this->GetProfiledCallSiteCount());
  731. }
  732. if (callSiteData->GetLdFldInlinees())
  733. {
  734. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, callSiteData, callSiteData->GetLdFldInlinees(), this->GetInlineCacheCount());
  735. }
  736. if (callSiteData->GetCallbackInlinees())
  737. {
  738. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, callSiteData, callSiteData->GetCallbackInlinees(), this->GetProfiledCallSiteCount());
  739. }
  740. if (callSiteData->GetCallApplyTargetInlinees())
  741. {
  742. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, callSiteData, callSiteData->GetCallApplyTargetInlinees(), this->GetProfiledCallApplyCallSiteCount());
  743. }
  744. }
  745. // Now walk the top-level data, but only do it once, since it's always the same.
  746. if (this->TestAndUpdateActiveFunctions(pActiveFuncs))
  747. {
  748. return;
  749. }
  750. {
  751. Field(FunctionCodeGenRuntimeData*)* data = this->GetCodeGenRuntimeData();
  752. if (data != nullptr)
  753. {
  754. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, nullptr, data, this->GetProfiledCallSiteCount());
  755. }
  756. }
  757. {
  758. Field(FunctionCodeGenRuntimeData*)* data = this->GetCodeGenGetSetRuntimeData();
  759. if (data != nullptr)
  760. {
  761. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, nullptr, data, this->GetInlineCacheCount());
  762. }
  763. }
  764. {
  765. Field(FunctionCodeGenRuntimeData*)* data = this->GetCodeGenCallbackRuntimeData();
  766. if (data != nullptr)
  767. {
  768. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, nullptr, data, this->GetProfiledCallSiteCount());
  769. }
  770. }
  771. {
  772. #if ENABLE_NATIVE_CODEGEN
  773. Field(FunctionCodeGenRuntimeData*)* data = this->GetCodeGenCallApplyTargetRuntimeData();
  774. if (data != nullptr)
  775. {
  776. this->UpdateActiveFunctionsForOneDataSet(pActiveFuncs, nullptr, data, this->GetProfiledCallApplyCallSiteCount());
  777. }
  778. #endif
  779. }
  780. }
  781. bool FunctionBody::DoRedeferFunction(uint inactiveThreshold) const
  782. {
  783. if (!(this->GetFunctionInfo()->GetFunctionProxy() == this &&
  784. this->CanBeDeferred() &&
  785. this->GetByteCode() &&
  786. this->GetCanDefer()))
  787. {
  788. return false;
  789. }
  790. if (!PHASE_FORCE(Js::RedeferralPhase, this) && !PHASE_STRESS(Js::RedeferralPhase, this))
  791. {
  792. uint compileCount = this->GetCompileCount();
  793. if (compileCount >= (uint)CONFIG_FLAG(RedeferralCap))
  794. {
  795. return false;
  796. }
  797. // Redeferral threshold is k^x, where x is the number of previous compiles.
  798. bool overflow = false;
  799. uint currentThreshold = inactiveThreshold;
  800. if (compileCount > 1)
  801. {
  802. currentThreshold = JavascriptNumber::DirectPowIntInt(&overflow, inactiveThreshold, compileCount);
  803. }
  804. if (overflow)
  805. {
  806. currentThreshold = 0xFFFFFFFF;
  807. }
  808. if (this->GetInactiveCount() < currentThreshold)
  809. {
  810. return false;
  811. }
  812. }
  813. // Make sure the function won't be jitted
  814. bool isJitCandidate = false;
  815. #if ENABLE_NATIVE_CODEGEN
  816. bool isJitModeFunction = !this->IsInterpreterExecutionMode();
  817. isJitCandidate = MapEntryPointsUntil([=](int index, FunctionEntryPointInfo *entryPointInfo)
  818. {
  819. if ((entryPointInfo->IsCodeGenPending() && isJitModeFunction) || entryPointInfo->IsCodeGenQueued() || entryPointInfo->IsCodeGenRecorded() || (entryPointInfo->IsCodeGenDone() && !entryPointInfo->IsNativeEntryPointProcessed()))
  820. {
  821. return true;
  822. }
  823. return false;
  824. });
  825. if (!isJitCandidate)
  826. {
  827. // Now check loop body entry points
  828. isJitCandidate = MapLoopHeadersUntil([=](uint loopNumber, LoopHeader* header)
  829. {
  830. return header->MapEntryPointsUntil([&](int index, LoopEntryPointInfo* entryPointInfo)
  831. {
  832. if (entryPointInfo->IsCodeGenPending() || entryPointInfo->IsCodeGenQueued() || entryPointInfo->IsCodeGenRecorded() || (entryPointInfo->IsCodeGenDone() && !entryPointInfo->IsNativeEntryPointProcessed()))
  833. {
  834. return true;
  835. }
  836. return false;
  837. });
  838. });
  839. }
  840. #endif
  841. return !isJitCandidate;
  842. }
  843. void FunctionBody::RedeferFunction()
  844. {
  845. Assert(this->CanBeDeferred());
  846. #if DBG
  847. if (PHASE_STATS(RedeferralPhase, this))
  848. {
  849. ThreadContext * threadContext = this->GetScriptContext()->GetThreadContext();
  850. threadContext->redeferredFunctions++;
  851. threadContext->recoveredBytes += sizeof(*this) + this->GetInlineCacheCount() * sizeof(InlineCache);
  852. if (this->byteCodeBlock)
  853. {
  854. threadContext->recoveredBytes += this->byteCodeBlock->GetLength();
  855. if (this->GetAuxiliaryData())
  856. {
  857. threadContext->recoveredBytes += this->GetAuxiliaryData()->GetLength();
  858. }
  859. }
  860. this->MapEntryPoints([&](int index, FunctionEntryPointInfo * info) {
  861. threadContext->recoveredBytes += sizeof(info);
  862. });
  863. // TODO: Get size of polymorphic caches, jitted code, etc.
  864. }
  865. // We can't get here if the function is being jitted. Jitting was either completed or not begun.
  866. this->UnlockCounters();
  867. #endif
  868. PHASE_PRINT_TRACE(Js::RedeferralPhase, this, _u("Redeferring function %d.%d: %s\n"),
  869. GetSourceContextId(), GetLocalFunctionId(),
  870. GetDisplayName() ? GetDisplayName() : _u("Anonymous function)"));
  871. ParseableFunctionInfo * parseableFunctionInfo =
  872. Js::ParseableFunctionInfo::NewDeferredFunctionFromFunctionBody(this);
  873. FunctionInfo * functionInfo = this->GetFunctionInfo();
  874. this->RedeferFunctionObjectTypes();
  875. this->Cleanup(false);
  876. if (GetIsFuncRegistered())
  877. {
  878. this->GetUtf8SourceInfo()->RemoveFunctionBody(this);
  879. }
  880. // New allocation is done at this point, so update existing structures
  881. // Adjust functionInfo attributes, point to new proxy
  882. functionInfo->SetAttributes((FunctionInfo::Attributes)(functionInfo->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
  883. functionInfo->SetFunctionProxy(parseableFunctionInfo);
  884. functionInfo->SetOriginalEntryPoint(DefaultEntryThunk);
  885. }
  886. void FunctionBody::RedeferFunctionObjectTypes()
  887. {
  888. this->MapFunctionObjectTypes([&](ScriptFunctionType* functionType)
  889. {
  890. Assert(functionType->GetTypeId() == TypeIds_Function);
  891. if (!CrossSite::IsThunk(functionType->GetEntryPoint()))
  892. {
  893. functionType->SetEntryPoint(GetScriptContext()->DeferredParsingThunk);
  894. }
  895. if (!CrossSite::IsThunk(functionType->GetEntryPointInfo()->jsMethod))
  896. {
  897. functionType->GetEntryPointInfo()->jsMethod = GetScriptContext()->DeferredParsingThunk;
  898. }
  899. });
  900. }
  901. void FunctionBody::SetDefaultFunctionEntryPointInfo(FunctionEntryPointInfo* entryPointInfo, const JavascriptMethod originalEntryPoint)
  902. {
  903. Assert(entryPointInfo);
  904. // Need to set twice since ProxyEntryPointInfo cast points to an interior pointer
  905. this->m_defaultEntryPointInfo = (ProxyEntryPointInfo*) entryPointInfo;
  906. this->defaultFunctionEntryPointInfo = entryPointInfo;
  907. SetOriginalEntryPoint(originalEntryPoint);
  908. }
  909. Var
  910. FunctionBody::GetFormalsPropIdArrayOrNullObj()
  911. {
  912. Var formalsPropIdArray = this->GetAuxPtrWithLock<AuxPointerType::FormalsPropIdArray>();
  913. if (formalsPropIdArray == nullptr)
  914. {
  915. return GetScriptContext()->GetLibrary()->GetNull();
  916. }
  917. return formalsPropIdArray;
  918. }
  919. PropertyIdArray*
  920. FunctionBody::GetFormalsPropIdArray(bool checkForNull)
  921. {
  922. if (checkForNull)
  923. {
  924. Assert(this->GetAuxPtrWithLock<AuxPointerType::FormalsPropIdArray>());
  925. }
  926. return this->GetAuxPtrWithLock<AuxPointerType::FormalsPropIdArray>();
  927. }
  928. void
  929. FunctionBody::SetFormalsPropIdArray(PropertyIdArray * propIdArray)
  930. {
  931. AssertMsg(propIdArray == nullptr || this->GetAuxPtrWithLock<AuxPointerType::FormalsPropIdArray>() == nullptr, "Already set?");
  932. this->SetAuxPtr<AuxPointerType::FormalsPropIdArray>(propIdArray);
  933. }
  934. ByteBlock*
  935. FunctionBody::GetByteCode() const
  936. {
  937. return this->byteCodeBlock;
  938. }
  939. // Returns original bytecode without probes (such as BPs).
  940. ByteBlock*
  941. FunctionBody::GetOriginalByteCode()
  942. {
  943. if (m_sourceInfo.m_probeBackingBlock)
  944. {
  945. return m_sourceInfo.m_probeBackingBlock;
  946. }
  947. else
  948. {
  949. return this->GetByteCode();
  950. }
  951. }
  952. // Returns a raw pointer to the display name which may not have a well-known lifetime. It's safer to use
  953. // GetExternalDisplayNameObject if the end goal is to create an object anyway.
  954. const char16* ParseableFunctionInfo::GetExternalDisplayName() const
  955. {
  956. return GetExternalDisplayName(this);
  957. }
  958. // Allocates a new JavascriptString object containing the display name associated with the FunctionBody.
  959. JavascriptString* ParseableFunctionInfo::GetExternalDisplayNameObject(ScriptContext* scriptContext) const
  960. {
  961. const char16* name = GetExternalDisplayName();
  962. if (!GetDisplayNameIsRecyclerAllocated() && !IsConstantFunctionName(name))
  963. {
  964. // The string is allocated in memory that we don't directly control the lifetime of. Copy the string to
  965. // ensure that the buffer remains valid for the lifetime of the object.
  966. return Js::JavascriptString::NewCopySz(name, scriptContext);
  967. }
  968. else
  969. {
  970. // Use the incoming buffer directly to create the object. This only works when the lifetime of the data is
  971. // static or GC allocated.
  972. return Js::JavascriptString::NewWithSz(name, scriptContext);
  973. }
  974. }
  975. RegSlot
  976. FunctionBody::GetLocalsCount()
  977. {
  978. return GetConstantCount() + GetVarCount();
  979. }
  980. RegSlot
  981. FunctionBody::GetVarCount()
  982. {
  983. return this->GetCountField(CounterFields::VarCount);
  984. }
  985. // Returns the number of non-temp local vars.
  986. uint32
  987. FunctionBody::GetNonTempLocalVarCount()
  988. {
  989. Assert(this->GetEndNonTempLocalIndex() >= this->GetFirstNonTempLocalIndex());
  990. return this->GetEndNonTempLocalIndex() - this->GetFirstNonTempLocalIndex();
  991. }
  992. uint32
  993. FunctionBody::GetFirstNonTempLocalIndex()
  994. {
  995. // First local var starts when the const vars end.
  996. return GetConstantCount();
  997. }
  998. uint32
  999. FunctionBody::GetEndNonTempLocalIndex()
  1000. {
  1001. // It will give the index on which current non temp locals ends, which is a first temp reg.
  1002. RegSlot firstTmpReg = GetFirstTmpRegister();
  1003. return firstTmpReg != Constants::NoRegister ? firstTmpReg : GetLocalsCount();
  1004. }
  1005. bool
  1006. FunctionBody::IsNonTempLocalVar(uint32 varIndex)
  1007. {
  1008. return GetFirstNonTempLocalIndex() <= varIndex && varIndex < GetEndNonTempLocalIndex();
  1009. }
  1010. bool
  1011. FunctionBody::GetSlotOffset(RegSlot slotId, int32 * slotOffset, bool allowTemp)
  1012. {
  1013. if (IsNonTempLocalVar(slotId) || allowTemp)
  1014. {
  1015. *slotOffset = (slotId - GetFirstNonTempLocalIndex()) * DIAGLOCALSLOTSIZE;
  1016. return true;
  1017. }
  1018. return false;
  1019. }
  1020. void
  1021. FunctionBody::CheckAndSetConstantCount(RegSlot cNewConstants) // New register count
  1022. {
  1023. CheckNotExecuting();
  1024. AssertMsg(GetConstantCount() <= cNewConstants, "Cannot shrink register usage");
  1025. this->SetConstantCount(cNewConstants);
  1026. }
  1027. void
  1028. FunctionBody::SetConstantCount(RegSlot cNewConstants) // New register count
  1029. {
  1030. this->SetCountField(CounterFields::ConstantCount, cNewConstants);
  1031. }
  1032. void
  1033. FunctionBody::CheckAndSetVarCount(RegSlot cNewVars)
  1034. {
  1035. CheckNotExecuting();
  1036. AssertMsg(this->GetVarCount() <= cNewVars, "Cannot shrink register usage");
  1037. this->SetVarCount(cNewVars);
  1038. }
  1039. void
  1040. FunctionBody::SetVarCount(RegSlot cNewVars) // New register count
  1041. {
  1042. this->SetCountField(FunctionBody::CounterFields::VarCount, cNewVars);
  1043. }
  1044. RegSlot
  1045. FunctionBody::GetYieldRegister()
  1046. {
  1047. return GetEndNonTempLocalIndex() - 1;
  1048. }
  1049. RegSlot
  1050. FunctionBody::GetFirstTmpReg()
  1051. {
  1052. AssertMsg(GetFirstTmpRegister() != Constants::NoRegister, "First temp hasn't been set yet");
  1053. return GetFirstTmpRegister();
  1054. }
  1055. void
  1056. FunctionBody::SetFirstTmpReg(
  1057. RegSlot firstTmpReg)
  1058. {
  1059. CheckNotExecuting();
  1060. AssertMsg(GetFirstTmpRegister() == Constants::NoRegister, "Should not be resetting the first temp");
  1061. SetFirstTmpRegister(firstTmpReg);
  1062. }
  1063. RegSlot
  1064. FunctionBody::GetTempCount()
  1065. {
  1066. return GetLocalsCount() - GetFirstTmpRegister();
  1067. }
  1068. void
  1069. FunctionBody::SetOutParamMaxDepth(RegSlot cOutParamsDepth)
  1070. {
  1071. #if _M_X64
  1072. constexpr RegSlot minAsmJsOutParams = MinAsmJsOutParams();
  1073. if (GetIsAsmJsFunction() && cOutParamsDepth < minAsmJsOutParams)
  1074. {
  1075. cOutParamsDepth = minAsmJsOutParams;
  1076. }
  1077. #endif
  1078. SetCountField(CounterFields::OutParamMaxDepth, cOutParamsDepth);
  1079. }
  1080. void
  1081. FunctionBody::CheckAndSetOutParamMaxDepth(RegSlot cOutParamsDepth)
  1082. {
  1083. CheckNotExecuting();
  1084. SetOutParamMaxDepth(cOutParamsDepth);
  1085. }
  1086. RegSlot
  1087. FunctionBody::GetOutParamMaxDepth()
  1088. {
  1089. return GetCountField(CounterFields::OutParamMaxDepth);
  1090. }
  1091. ModuleID
  1092. FunctionBody::GetModuleID() const
  1093. {
  1094. return this->GetHostSrcInfo()->moduleID;
  1095. }
  1096. ///----------------------------------------------------------------------------
  1097. ///
  1098. /// FunctionBody::BeginExecution
  1099. ///
  1100. /// BeginExecution() is called by InterpreterStackFrame when a function begins execution.
  1101. /// - Once started execution, the function may not be modified, as it would
  1102. /// change the stack-frame layout:
  1103. /// - This is a debug-only check because of the runtime cost. At release time,
  1104. /// a stack-walk will be performed by GC to determine which functions are
  1105. /// executing.
  1106. ///
  1107. ///----------------------------------------------------------------------------
  1108. void
  1109. FunctionBody::BeginExecution()
  1110. {
  1111. #if DBG
  1112. m_DEBUG_executionCount++;
  1113. this->LockDownCounters();
  1114. #endif
  1115. // Don't allow loop headers to be released while the function is executing
  1116. ::InterlockedIncrement(&this->m_depth);
  1117. }
  1118. ///----------------------------------------------------------------------------
  1119. ///
  1120. /// FunctionBody::CheckEmpty
  1121. ///
  1122. /// CheckEmpty() validates that the given instance has not been given an
  1123. /// implementation yet.
  1124. ///
  1125. ///----------------------------------------------------------------------------
  1126. void
  1127. FunctionBody::CheckEmpty()
  1128. {
  1129. AssertMsg((this->byteCodeBlock == nullptr) && (this->GetAuxiliaryData() == nullptr) && (this->GetAuxiliaryContextData() == nullptr), "Function body may only be set once");
  1130. }
  1131. ///----------------------------------------------------------------------------
  1132. ///
  1133. /// FunctionBody::CheckNotExecuting
  1134. ///
  1135. /// CheckNotExecuting() checks that function is not currently executing when it
  1136. /// is being modified. See BeginExecution() for details.
  1137. ///
  1138. ///----------------------------------------------------------------------------
  1139. void
  1140. FunctionBody::CheckNotExecuting()
  1141. {
  1142. AssertMsg(m_DEBUG_executionCount == 0, "Function cannot be executing when modified");
  1143. }
  1144. ///----------------------------------------------------------------------------
  1145. ///
  1146. /// FunctionBody::EndExecution
  1147. ///
  1148. /// EndExecution() is called by InterpreterStackFrame when a function ends execution.
  1149. /// See BeginExecution() for details.
  1150. ///
  1151. ///----------------------------------------------------------------------------
  1152. void
  1153. FunctionBody::EndExecution()
  1154. {
  1155. #if DBG
  1156. AssertMsg(m_DEBUG_executionCount > 0, "Must have a previous execution to end");
  1157. m_DEBUG_executionCount--;
  1158. #endif
  1159. uint depth = ::InterlockedDecrement(&this->m_depth);
  1160. // If loop headers were determined to be no longer needed
  1161. // during the execution of the function, we release them now
  1162. if (depth == 0 && this->m_pendingLoopHeaderRelease)
  1163. {
  1164. this->m_pendingLoopHeaderRelease = false;
  1165. ReleaseLoopHeaders();
  1166. }
  1167. }
  1168. void FunctionBody::AddEntryPointToEntryPointList(FunctionEntryPointInfo* entryPointInfo)
  1169. {
  1170. ThreadContext::AutoDisableExpiration disableExpiration(this->m_scriptContext->GetThreadContext());
  1171. Recycler* recycler = this->m_scriptContext->GetRecycler();
  1172. entryPointInfo->entryPointIndex = this->entryPoints->Add(recycler->CreateWeakReferenceHandle(entryPointInfo));
  1173. }
  1174. #if DBG
  1175. BOOL FunctionBody::IsInterpreterThunk() const
  1176. {
  1177. bool isInterpreterThunk = this->GetOriginalEntryPoint_Unchecked() == DefaultEntryThunk;
  1178. #if DYNAMIC_INTERPRETER_THUNK
  1179. bool isStaticInterpreterThunk = this->GetOriginalEntryPoint_Unchecked() == InterpreterStackFrame::StaticInterpreterThunk;
  1180. isInterpreterThunk = isInterpreterThunk || isStaticInterpreterThunk || IsDynamicInterpreterThunk();
  1181. #endif
  1182. return isInterpreterThunk;
  1183. }
  1184. BOOL FunctionBody::IsDynamicInterpreterThunk() const
  1185. {
  1186. #if DYNAMIC_INTERPRETER_THUNK
  1187. return this->GetScriptContext()->IsDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked());
  1188. #else
  1189. return FALSE;
  1190. #endif
  1191. }
  1192. #endif
  1193. FunctionEntryPointInfo * FunctionBody::TryGetEntryPointInfo(int index) const
  1194. {
  1195. // If we've already freed the recyclable data, we're shutting down the script context so skip clean up
  1196. if (this->entryPoints == nullptr) return 0;
  1197. Assert(index < this->entryPoints->Count());
  1198. FunctionEntryPointInfo* entryPoint = this->entryPoints->Item(index)->Get();
  1199. return entryPoint;
  1200. }
  1201. FunctionEntryPointInfo * FunctionBody::GetEntryPointInfo(int index) const
  1202. {
  1203. FunctionEntryPointInfo* entryPoint = TryGetEntryPointInfo(index);
  1204. Assert(entryPoint);
  1205. return entryPoint;
  1206. }
  1207. #if ENABLE_NATIVE_CODEGEN
  1208. uint32 FunctionBody::GetFrameHeight(EntryPointInfo* entryPointInfo) const
  1209. {
  1210. return entryPointInfo->GetNativeEntryPointData()->GetFrameHeight();
  1211. }
  1212. void
  1213. FunctionBody::SetNativeThrowSpanSequence(SmallSpanSequence *seq, uint loopNum, LoopEntryPointInfo* entryPoint)
  1214. {
  1215. Assert(loopNum != LoopHeader::NoLoop);
  1216. LoopHeader *loopHeader = this->GetLoopHeaderWithLock(loopNum);
  1217. Assert(loopHeader);
  1218. Assert(entryPoint->loopHeader == loopHeader);
  1219. entryPoint->SetNativeThrowSpanSequence(seq);
  1220. }
  1221. void
  1222. FunctionBody::RecordNativeThrowMap(SmallSpanSequenceIter& iter, uint32 nativeOffset, uint32 statementIndex, EntryPointInfo* entryPoint, uint loopNum)
  1223. {
  1224. SmallSpanSequence *pSpanSequence;
  1225. pSpanSequence = entryPoint->GetNativeThrowSpanSequence();
  1226. if (!pSpanSequence)
  1227. {
  1228. if (statementIndex == -1)
  1229. {
  1230. return; // No need to initialize native throw map for non-user code
  1231. }
  1232. pSpanSequence = HeapNew(SmallSpanSequence);
  1233. if (loopNum == LoopHeader::NoLoop)
  1234. {
  1235. ((FunctionEntryPointInfo*) entryPoint)->SetNativeThrowSpanSequence(pSpanSequence);
  1236. }
  1237. else
  1238. {
  1239. this->SetNativeThrowSpanSequence(pSpanSequence, loopNum, (LoopEntryPointInfo*) entryPoint);
  1240. }
  1241. }
  1242. else if (iter.accumulatedSourceBegin == static_cast<int>(statementIndex))
  1243. {
  1244. return; // Compress adjacent spans which share the same statementIndex
  1245. }
  1246. StatementData data;
  1247. data.sourceBegin = static_cast<int>(statementIndex); // sourceBegin represents statementIndex here
  1248. data.bytecodeBegin = static_cast<int>(nativeOffset); // bytecodeBegin represents nativeOffset here
  1249. pSpanSequence->RecordARange(iter, &data);
  1250. }
  1251. #endif
  1252. PropertyId
  1253. ParseableFunctionInfo::GetOrAddPropertyIdTracked(JsUtil::CharacterBuffer<WCHAR> const& propName)
  1254. {
  1255. const Js::PropertyRecord* propRecord = nullptr;
  1256. ScriptContext * scriptContext = this->m_scriptContext;
  1257. scriptContext->GetOrAddPropertyRecord(propName, &propRecord);
  1258. PropertyId propertyId = propRecord->GetPropertyId();
  1259. if (!scriptContext->IsTrackedPropertyId(propertyId))
  1260. {
  1261. this->m_utf8SourceInfo->GetBoundedPropertyRecordHashSet()->Item(propRecord);
  1262. }
  1263. return propertyId;
  1264. }
  1265. SmallSpanSequence::SmallSpanSequence()
  1266. : pStatementBuffer(nullptr),
  1267. pActualOffsetList(nullptr),
  1268. baseValue(0)
  1269. {
  1270. }
  1271. BOOL SmallSpanSequence::RecordARange(SmallSpanSequenceIter &iter, StatementData * data)
  1272. {
  1273. Assert(data);
  1274. if (!this->pStatementBuffer)
  1275. {
  1276. this->pStatementBuffer = JsUtil::GrowingUint32HeapArray::Create(4);
  1277. baseValue = data->sourceBegin;
  1278. Reset(iter);
  1279. }
  1280. SmallSpan span(0);
  1281. span.sourceBegin = GetDiff(data->sourceBegin, iter.accumulatedSourceBegin);
  1282. span.bytecodeBegin = GetDiff(data->bytecodeBegin, iter.accumulatedBytecodeBegin);
  1283. this->pStatementBuffer->Add((uint32)span);
  1284. // Update iterator for the next set
  1285. iter.accumulatedSourceBegin = data->sourceBegin;
  1286. iter.accumulatedBytecodeBegin = data->bytecodeBegin;
  1287. return TRUE;
  1288. }
  1289. // FunctionProxy methods
  1290. ScriptContext*
  1291. FunctionProxy::GetScriptContext() const
  1292. {
  1293. return m_scriptContext;
  1294. }
  1295. void FunctionProxy::Copy(FunctionProxy* other)
  1296. {
  1297. Assert(other);
  1298. other->SetIsTopLevel(this->m_isTopLevel);
  1299. if (this->IsPublicLibraryCode())
  1300. {
  1301. other->SetIsPublicLibraryCode();
  1302. }
  1303. if (this->IsJsBuiltInCode())
  1304. {
  1305. other->SetIsJsBuiltInCode();
  1306. }
  1307. #define CopyDeferParseField(field) other->field = this->field;
  1308. CopyDeferParseField(deferredPrototypeType);
  1309. CopyDeferParseField(undeferredFunctionType);
  1310. #undef CopyDeferParseField
  1311. other->SetFunctionObjectTypeList(this->GetFunctionObjectTypeList());
  1312. }
  1313. void ParseableFunctionInfo::Copy(ParseableFunctionInfo * other)
  1314. {
  1315. __super::Copy(other);
  1316. #define CopyDeferParseField(field) other->field = this->field;
  1317. CopyDeferParseField(flags);
  1318. CopyDeferParseField(crossSiteDeferredFunctionType);
  1319. CopyDeferParseField(crossSiteUndeferredFunctionType);
  1320. CopyDeferParseField(m_isDeclaration);
  1321. CopyDeferParseField(m_isAccessor);
  1322. CopyDeferParseField(m_isStrictMode);
  1323. CopyDeferParseField(m_isGlobalFunc);
  1324. CopyDeferParseField(m_doBackendArgumentsOptimization);
  1325. CopyDeferParseField(m_doScopeObjectCreation);
  1326. CopyDeferParseField(m_usesArgumentsObject);
  1327. CopyDeferParseField(m_isEval);
  1328. CopyDeferParseField(m_isDynamicFunction);
  1329. CopyDeferParseField(m_hasImplicitArgIns);
  1330. CopyDeferParseField(m_dontInline);
  1331. CopyDeferParseField(m_inParamCount);
  1332. CopyDeferParseField(m_grfscr);
  1333. other->SetScopeInfo(this->GetScopeInfo());
  1334. other->SetDeferredStubs(this->GetDeferredStubs());
  1335. CopyDeferParseField(m_utf8SourceHasBeenSet);
  1336. #if DBG
  1337. CopyDeferParseField(deferredParseNextFunctionId);
  1338. CopyDeferParseField(scopeObjectSize);
  1339. #endif
  1340. CopyDeferParseField(scopeSlotArraySize);
  1341. CopyDeferParseField(paramScopeSlotArraySize);
  1342. other->SetCachedSourceStringWeakRef(this->GetCachedSourceStringWeakRef());
  1343. CopyDeferParseField(m_isAsmjsMode);
  1344. CopyDeferParseField(m_isAsmJsFunction);
  1345. PropertyId * propertyIds = this->GetPropertyIdsForScopeSlotArray();
  1346. if (propertyIds != nullptr)
  1347. {
  1348. other->SetPropertyIdsForScopeSlotArray(propertyIds, this->scopeSlotArraySize, this->paramScopeSlotArraySize);
  1349. }
  1350. CopyDeferParseField(m_sourceIndex);
  1351. CopyDeferParseField(m_cchStartOffset);
  1352. CopyDeferParseField(m_cchLength);
  1353. CopyDeferParseField(m_lineNumber);
  1354. CopyDeferParseField(m_columnNumber);
  1355. CopyDeferParseField(m_cbStartOffset);
  1356. CopyDeferParseField(m_cbStartPrintOffset);
  1357. CopyDeferParseField(m_cbLength);
  1358. this->CopyNestedArray(other);
  1359. #undef CopyDeferParseField
  1360. }
  1361. void ParseableFunctionInfo::Copy(FunctionBody* other)
  1362. {
  1363. this->Copy(static_cast<ParseableFunctionInfo*>(other));
  1364. other->CopySourceInfo(this);
  1365. }
  1366. void ParseableFunctionInfo::CopyNestedArray(ParseableFunctionInfo * other)
  1367. {
  1368. NestedArray * thisNestedArray = this->GetNestedArray();
  1369. NestedArray * otherNestedArray = other->GetNestedArray();
  1370. if (thisNestedArray == nullptr)
  1371. {
  1372. Assert(otherNestedArray == nullptr);
  1373. return;
  1374. }
  1375. Assert(otherNestedArray->nestedCount == thisNestedArray->nestedCount);
  1376. for (uint i = 0; i < thisNestedArray->nestedCount; i++)
  1377. {
  1378. otherNestedArray->functionInfoArray[i] = thisNestedArray->functionInfoArray[i];
  1379. }
  1380. }
  1381. // DeferDeserializeFunctionInfo methods
  1382. DeferDeserializeFunctionInfo::DeferDeserializeFunctionInfo(int nestedCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, FunctionInfo::Attributes attributes) :
  1383. FunctionProxy(scriptContext, sourceInfo, functionNumber),
  1384. m_cache(byteCodeCache),
  1385. m_functionBytes(serializedFunction),
  1386. m_displayName(nullptr),
  1387. m_displayNameLength(0),
  1388. m_nativeModule(nativeModule)
  1389. {
  1390. this->functionInfo = RecyclerNew(scriptContext->GetRecycler(), FunctionInfo, DefaultDeferredDeserializeThunk, (FunctionInfo::Attributes)(attributes | FunctionInfo::Attributes::DeferredDeserialize), functionId, this);
  1391. this->m_defaultEntryPointInfo = RecyclerNew(scriptContext->GetRecycler(), ProxyEntryPointInfo, DefaultDeferredDeserializeThunk);
  1392. PERF_COUNTER_INC(Code, DeferDeserializeFunctionProxy);
  1393. SetDisplayName(displayName, displayNameLength, displayShortNameOffset, FunctionProxy::SetDisplayNameFlagsDontCopy);
  1394. }
  1395. DeferDeserializeFunctionInfo* DeferDeserializeFunctionInfo::New(ScriptContext* scriptContext, int nestedCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, FunctionInfo::Attributes attributes)
  1396. {
  1397. return RecyclerNewFinalized(scriptContext->GetRecycler(),
  1398. DeferDeserializeFunctionInfo,
  1399. nestedCount,
  1400. functionId,
  1401. byteCodeCache,
  1402. serializedFunction,
  1403. sourceInfo,
  1404. scriptContext,
  1405. scriptContext->GetThreadContext()->NewFunctionNumber(),
  1406. displayName,
  1407. displayNameLength,
  1408. displayShortNameOffset,
  1409. nativeModule,
  1410. attributes);
  1411. }
  1412. const char16*
  1413. DeferDeserializeFunctionInfo::GetDisplayName() const
  1414. {
  1415. return this->m_displayName;
  1416. }
  1417. // ParseableFunctionInfo methods
  1418. ParseableFunctionInfo::ParseableFunctionInfo(JavascriptMethod entryPoint, int nestedCount,
  1419. LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber,
  1420. const char16* displayName, uint displayNameLength, uint displayShortNameOffset, FunctionInfo::Attributes attributes, FunctionBodyFlags flags) :
  1421. FunctionProxy(scriptContext, sourceInfo, functionNumber),
  1422. crossSiteDeferredFunctionType(nullptr),
  1423. crossSiteUndeferredFunctionType(nullptr),
  1424. #if DYNAMIC_INTERPRETER_THUNK
  1425. m_dynamicInterpreterThunk(nullptr),
  1426. #endif
  1427. flags(flags),
  1428. m_hasBeenParsed(false),
  1429. m_isGlobalFunc(false),
  1430. m_isDeclaration(false),
  1431. m_isNamedFunctionExpression(false),
  1432. m_isNameIdentifierRef (true),
  1433. m_isStaticNameFunction(false),
  1434. m_doBackendArgumentsOptimization(true),
  1435. m_doScopeObjectCreation(true),
  1436. m_usesArgumentsObject(false),
  1437. m_isStrictMode(false),
  1438. m_isAsmjsMode(false),
  1439. m_dontInline(false),
  1440. m_hasImplicitArgIns(true),
  1441. m_grfscr(0),
  1442. m_inParamCount(0),
  1443. m_reportedInParamCount(0),
  1444. m_sourceIndex(Js::Constants::InvalidSourceIndex),
  1445. m_utf8SourceHasBeenSet(false),
  1446. m_cchLength(0),
  1447. m_cbLength(0),
  1448. m_cchStartOffset(0),
  1449. m_cbStartOffset(0),
  1450. m_cbStartPrintOffset(0),
  1451. m_lineNumber(0),
  1452. m_columnNumber(0),
  1453. m_isEval(false),
  1454. m_isDynamicFunction(false),
  1455. m_displayName(nullptr),
  1456. m_displayNameLength(0),
  1457. m_displayShortNameOffset(0),
  1458. scopeSlotArraySize(0),
  1459. paramScopeSlotArraySize(0),
  1460. m_reparsed(false),
  1461. m_isAsmJsFunction(false),
  1462. m_tag21(true),
  1463. m_isMethod(false)
  1464. #if DBG
  1465. ,m_wasEverAsmjsMode(false)
  1466. ,scopeObjectSize(0)
  1467. #endif
  1468. {
  1469. this->functionInfo = RecyclerNew(scriptContext->GetRecycler(), FunctionInfo, entryPoint, attributes, functionId, this);
  1470. if (nestedCount > 0)
  1471. {
  1472. nestedArray = RecyclerNewPlusZ(m_scriptContext->GetRecycler(),
  1473. nestedCount*sizeof(FunctionProxy*), NestedArray, nestedCount);
  1474. }
  1475. else
  1476. {
  1477. nestedArray = nullptr;
  1478. }
  1479. if ((attributes & Js::FunctionInfo::DeferredParse) == 0)
  1480. {
  1481. this->m_defaultEntryPointInfo = RecyclerNewFinalized(scriptContext->GetRecycler(),
  1482. FunctionEntryPointInfo, this, entryPoint, scriptContext->GetThreadContext());
  1483. }
  1484. else
  1485. {
  1486. this->m_defaultEntryPointInfo = RecyclerNew(scriptContext->GetRecycler(), ProxyEntryPointInfo, entryPoint);
  1487. }
  1488. SetDisplayName(displayName, displayNameLength, displayShortNameOffset);
  1489. this->SetOriginalEntryPoint(DefaultEntryThunk);
  1490. }
  1491. ParseableFunctionInfo::ParseableFunctionInfo(ParseableFunctionInfo * proxy) :
  1492. FunctionProxy(proxy->GetScriptContext(), proxy->GetUtf8SourceInfo(), proxy->GetFunctionNumber()),
  1493. #if DYNAMIC_INTERPRETER_THUNK
  1494. m_dynamicInterpreterThunk(nullptr),
  1495. #endif
  1496. m_hasBeenParsed(false),
  1497. m_isNamedFunctionExpression(proxy->GetIsNamedFunctionExpression()),
  1498. m_isNameIdentifierRef (proxy->GetIsNameIdentifierRef()),
  1499. m_isStaticNameFunction(proxy->GetIsStaticNameFunction()),
  1500. m_reportedInParamCount(proxy->GetReportedInParamsCount()),
  1501. m_reparsed(proxy->IsReparsed()),
  1502. m_isMethod(proxy->IsMethod()),
  1503. m_tag21(true)
  1504. #if DBG
  1505. , m_wasEverAsmjsMode(proxy->m_wasEverAsmjsMode)
  1506. #endif
  1507. {
  1508. FunctionInfo * functionInfo = proxy->GetFunctionInfo();
  1509. this->functionInfo = functionInfo;
  1510. uint nestedCount = proxy->GetNestedCount();
  1511. if (nestedCount > 0)
  1512. {
  1513. nestedArray = RecyclerNewPlusZ(m_scriptContext->GetRecycler(),
  1514. nestedCount*sizeof(FunctionProxy*), NestedArray, nestedCount);
  1515. }
  1516. else
  1517. {
  1518. nestedArray = nullptr;
  1519. }
  1520. proxy->Copy(this);
  1521. SetDisplayName(proxy->GetDisplayName(), proxy->GetDisplayNameLength(), proxy->GetShortDisplayNameOffset());
  1522. }
  1523. ParseableFunctionInfo* ParseableFunctionInfo::New(ScriptContext* scriptContext, int nestedCount,
  1524. LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, FunctionInfo::Attributes attributes, FunctionBodyFlags flags)
  1525. {
  1526. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  1527. Assert(
  1528. scriptContext->DeferredParsingThunk == ProfileDeferredParsingThunk ||
  1529. scriptContext->DeferredParsingThunk == DefaultDeferredParsingThunk);
  1530. #else
  1531. Assert(scriptContext->DeferredParsingThunk == DefaultDeferredParsingThunk);
  1532. #endif
  1533. #ifdef PERF_COUNTERS
  1534. PERF_COUNTER_INC(Code, DeferredFunction);
  1535. #endif
  1536. uint newFunctionNumber = scriptContext->GetThreadContext()->NewFunctionNumber();
  1537. if (!sourceInfo->GetSourceContextInfo()->IsDynamic())
  1538. {
  1539. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("Function was deferred from parsing - ID: %d; Display Name: %s; Utf8SourceInfo ID: %d; Source Length: %d; Source Url:%s\n"), newFunctionNumber, displayName, sourceInfo->GetSourceInfoId(), sourceInfo->GetCchLength(), sourceInfo->GetSourceContextInfo()->url);
  1540. }
  1541. else
  1542. {
  1543. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("Function was deferred from parsing - ID: %d; Display Name: %s; Utf8SourceInfo ID: %d; Source Length: %d;\n"), newFunctionNumber, displayName, sourceInfo->GetSourceInfoId(), sourceInfo->GetCchLength());
  1544. }
  1545. // When generating a new defer parse function, we always use a new function number
  1546. return RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(),
  1547. ParseableFunctionInfo,
  1548. scriptContext->DeferredParsingThunk,
  1549. nestedCount,
  1550. functionId,
  1551. sourceInfo,
  1552. scriptContext,
  1553. newFunctionNumber,
  1554. displayName,
  1555. displayNameLength,
  1556. displayShortNameOffset,
  1557. (FunctionInfo::Attributes)(attributes | FunctionInfo::Attributes::DeferredParse),
  1558. flags);
  1559. }
  1560. ParseableFunctionInfo *
  1561. ParseableFunctionInfo::NewDeferredFunctionFromFunctionBody(FunctionBody * functionBody)
  1562. {
  1563. ScriptContext * scriptContext = functionBody->GetScriptContext();
  1564. uint nestedCount = functionBody->GetNestedCount();
  1565. ParseableFunctionInfo * info = RecyclerNewWithBarrierFinalized(scriptContext->GetRecycler(),
  1566. ParseableFunctionInfo,
  1567. functionBody);
  1568. // Create new entry point info
  1569. info->m_defaultEntryPointInfo = RecyclerNew(scriptContext->GetRecycler(), ProxyEntryPointInfo, scriptContext->DeferredParsingThunk);
  1570. // Initialize nested function array, update back pointers
  1571. for (uint i = 0; i < nestedCount; i++)
  1572. {
  1573. FunctionInfo * nestedInfo = functionBody->GetNestedFunc(i);
  1574. info->SetNestedFunc(nestedInfo, i, 0);
  1575. }
  1576. // Update function objects
  1577. return info;
  1578. }
  1579. DWORD_PTR FunctionProxy::GetSecondaryHostSourceContext() const
  1580. {
  1581. return this->GetUtf8SourceInfo()->GetSecondaryHostSourceContext();
  1582. }
  1583. DWORD_PTR FunctionProxy::GetHostSourceContext() const
  1584. {
  1585. return this->GetSourceContextInfo()->dwHostSourceContext;
  1586. }
  1587. SourceContextInfo * FunctionProxy::GetSourceContextInfo() const
  1588. {
  1589. return this->GetHostSrcInfo()->sourceContextInfo;
  1590. }
  1591. SRCINFO const * FunctionProxy::GetHostSrcInfo() const
  1592. {
  1593. return this->GetUtf8SourceInfo()->GetSrcInfo();
  1594. }
  1595. //
  1596. // Returns the start line for the script buffer (code buffer for the entire script tag) of this current function.
  1597. // We subtract the lnMinHost because it is the number of lines we have added to augment scriptlets passed through
  1598. // ParseProcedureText to have a function name.
  1599. //
  1600. ULONG FunctionProxy::GetHostStartLine() const
  1601. {
  1602. return this->GetHostSrcInfo()->dlnHost - this->GetHostSrcInfo()->lnMinHost;
  1603. }
  1604. //
  1605. // Returns the start column of the first line for the script buffer of this current function.
  1606. //
  1607. ULONG FunctionProxy::GetHostStartColumn() const
  1608. {
  1609. return this->GetHostSrcInfo()->ulColumnHost;
  1610. }
  1611. //
  1612. // Returns line number in unmodified host buffer (i.e. without extra scriptlet code added by ParseProcedureText --
  1613. // when e.g. we add extra code for event handlers, such as "function onclick(event)\n{\n").
  1614. //
  1615. ULONG FunctionProxy::GetLineNumberInHostBuffer(ULONG relativeLineNumber) const
  1616. {
  1617. ULONG lineNumber = relativeLineNumber;
  1618. if (lineNumber >= this->GetHostSrcInfo()->lnMinHost)
  1619. {
  1620. lineNumber -= this->GetHostSrcInfo()->lnMinHost;
  1621. }
  1622. // Note that '<' is still a valid case -- that would be the case for onclick scriptlet function itself (lineNumber == 0).
  1623. return lineNumber;
  1624. }
  1625. ULONG FunctionProxy::ComputeAbsoluteLineNumber(ULONG relativeLineNumber) const
  1626. {
  1627. // We add 1 because the line numbers start from 0.
  1628. return this->GetHostSrcInfo()->dlnHost + GetLineNumberInHostBuffer(relativeLineNumber) + 1;
  1629. }
  1630. ULONG FunctionProxy::ComputeAbsoluteColumnNumber(ULONG relativeLineNumber, ULONG relativeColumnNumber) const
  1631. {
  1632. if (this->GetLineNumberInHostBuffer(relativeLineNumber) == 0)
  1633. {
  1634. // The host column matters only for the first line.
  1635. return this->GetHostStartColumn() + relativeColumnNumber + 1;
  1636. }
  1637. // We add 1 because the column numbers start from 0.
  1638. return relativeColumnNumber + 1;
  1639. }
  1640. //
  1641. // Returns the line number of the function declaration in the source file.
  1642. //
  1643. ULONG
  1644. ParseableFunctionInfo::GetLineNumber() const
  1645. {
  1646. return this->ComputeAbsoluteLineNumber(this->m_lineNumber);
  1647. }
  1648. //
  1649. // Returns the column number of the function declaration in the source file.
  1650. //
  1651. ULONG
  1652. ParseableFunctionInfo::GetColumnNumber() const
  1653. {
  1654. return ComputeAbsoluteColumnNumber(this->m_lineNumber, m_columnNumber);
  1655. }
  1656. LPCWSTR
  1657. ParseableFunctionInfo::GetSourceName() const
  1658. {
  1659. return GetSourceName(this->GetSourceContextInfo());
  1660. }
  1661. void
  1662. ParseableFunctionInfo::SetGrfscr(uint32 grfscr)
  1663. {
  1664. this->m_grfscr = grfscr;
  1665. }
  1666. uint32
  1667. ParseableFunctionInfo::GetGrfscr() const
  1668. {
  1669. return this->m_grfscr;
  1670. }
  1671. ProxyEntryPointInfo*
  1672. FunctionProxy::GetDefaultEntryPointInfo() const
  1673. {
  1674. return this->m_defaultEntryPointInfo;
  1675. }
  1676. FunctionEntryPointInfo*
  1677. FunctionBody::GetDefaultFunctionEntryPointInfo() const
  1678. {
  1679. Assert(((ProxyEntryPointInfo*) this->defaultFunctionEntryPointInfo) == this->m_defaultEntryPointInfo);
  1680. return this->defaultFunctionEntryPointInfo;
  1681. }
  1682. void
  1683. ParseableFunctionInfo::SetInParamsCount(ArgSlot newInParamCount)
  1684. {
  1685. AssertMsg(m_inParamCount <= newInParamCount, "Cannot shrink register usage");
  1686. m_inParamCount = newInParamCount;
  1687. if (newInParamCount <= 1)
  1688. {
  1689. SetHasImplicitArgIns(false);
  1690. }
  1691. }
  1692. ArgSlot
  1693. ParseableFunctionInfo::GetReportedInParamsCount() const
  1694. {
  1695. return m_reportedInParamCount;
  1696. }
  1697. void
  1698. ParseableFunctionInfo::SetReportedInParamsCount(ArgSlot newInParamCount)
  1699. {
  1700. AssertMsg(m_reportedInParamCount <= newInParamCount, "Cannot shrink register usage");
  1701. m_reportedInParamCount = newInParamCount;
  1702. }
  1703. void
  1704. ParseableFunctionInfo::ResetInParams()
  1705. {
  1706. m_inParamCount = 0;
  1707. m_reportedInParamCount = 0;
  1708. }
  1709. const char16*
  1710. ParseableFunctionInfo::GetDisplayName() const
  1711. {
  1712. return this->m_displayName;
  1713. }
  1714. void ParseableFunctionInfo::BuildDeferredStubs(ParseNodeFnc *pnodeFnc)
  1715. {
  1716. DeferredFunctionStub* deferredStubs = Parser::BuildDeferredStubTree(pnodeFnc, m_scriptContext->GetRecycler());
  1717. this->SetDeferredStubs(deferredStubs);
  1718. }
  1719. JavascriptString * ParseableFunctionInfo::GetCachedSourceString()
  1720. {
  1721. RecyclerWeakReference<JavascriptString> * weakRef = GetCachedSourceStringWeakRef();
  1722. if (weakRef)
  1723. {
  1724. JavascriptString * string = weakRef->Get();
  1725. if (string)
  1726. {
  1727. return string;
  1728. }
  1729. this->SetAuxPtr<AuxPointerType::CachedSourceString>(nullptr);
  1730. }
  1731. return nullptr;
  1732. }
  1733. void ParseableFunctionInfo::SetCachedSourceString(JavascriptString * sourceString)
  1734. {
  1735. Assert(this->GetCachedSourceString() == nullptr);
  1736. if (sourceString)
  1737. {
  1738. this->SetCachedSourceStringWeakRef(this->GetRecycler()->CreateWeakReferenceHandle(sourceString));
  1739. }
  1740. }
  1741. RecyclerWeakReference<JavascriptString> * ParseableFunctionInfo::GetCachedSourceStringWeakRef()
  1742. {
  1743. return this->GetAuxPtr<AuxPointerType::CachedSourceString>();
  1744. }
  1745. void ParseableFunctionInfo::SetCachedSourceStringWeakRef(RecyclerWeakReference<JavascriptString> * weakRef)
  1746. {
  1747. Assert(this->GetCachedSourceString() == nullptr);
  1748. this->SetAuxPtr<AuxPointerType::CachedSourceString>(weakRef);
  1749. }
  1750. FunctionInfoArray ParseableFunctionInfo::GetNestedFuncArray()
  1751. {
  1752. Assert(GetNestedArray() != nullptr);
  1753. return GetNestedArray()->functionInfoArray;
  1754. }
  1755. void ParseableFunctionInfo::SetNestedFunc(FunctionInfo* nestedFunc, uint index, uint32 flags)
  1756. {
  1757. AssertMsg(index < this->GetNestedCount(), "Trying to write past the nested func array");
  1758. FunctionInfoArray nested = this->GetNestedFuncArray();
  1759. nested[index] = nestedFunc;
  1760. }
  1761. FunctionInfo* ParseableFunctionInfo::GetNestedFunc(uint index)
  1762. {
  1763. return *(GetNestedFuncReference(index));
  1764. }
  1765. FunctionProxy* ParseableFunctionInfo::GetNestedFunctionProxy(uint index)
  1766. {
  1767. FunctionInfo *info = GetNestedFunc(index);
  1768. return info ? info->GetFunctionProxy() : nullptr;
  1769. }
  1770. FunctionInfoPtrPtr ParseableFunctionInfo::GetNestedFuncReference(uint index)
  1771. {
  1772. AssertMsg(index < this->GetNestedCount(), "Trying to write past the nested func array");
  1773. FunctionInfoArray nested = this->GetNestedFuncArray();
  1774. return &nested[index];
  1775. }
  1776. ParseableFunctionInfo* ParseableFunctionInfo::GetNestedFunctionForExecution(uint index)
  1777. {
  1778. FunctionInfo* currentNestedFunction = this->GetNestedFunc(index);
  1779. Assert(currentNestedFunction);
  1780. if (currentNestedFunction->IsDeferredDeserializeFunction())
  1781. {
  1782. currentNestedFunction->GetFunctionProxy()->EnsureDeserialized();
  1783. }
  1784. return currentNestedFunction->GetParseableFunctionInfo();
  1785. }
  1786. void
  1787. FunctionProxy::UpdateFunctionBodyImpl(FunctionBody * body)
  1788. {
  1789. FunctionInfo *functionInfo = this->GetFunctionInfo();
  1790. Assert(functionInfo->GetFunctionProxy() == this);
  1791. Assert(!this->IsFunctionBody() || body == this);
  1792. functionInfo->SetFunctionProxy(body);
  1793. body->SetFunctionInfo(functionInfo);
  1794. body->SetAttributes((FunctionInfo::Attributes)(functionInfo->GetAttributes() & ~(FunctionInfo::Attributes::DeferredParse | FunctionInfo::Attributes::DeferredDeserialize)));
  1795. }
  1796. //
  1797. // This method gets a function body for the purposes of execution
  1798. // It has an if within it to avoid making it a virtual- it's called from the interpreter
  1799. // It will cause the function info to get deserialized if it hasn't been deserialized
  1800. // already
  1801. //
  1802. ParseableFunctionInfo * FunctionProxy::EnsureDeserialized()
  1803. {
  1804. Assert(this == this->GetFunctionInfo()->GetFunctionProxy());
  1805. FunctionProxy * executionFunctionBody = this;
  1806. if (IsDeferredDeserializeFunction())
  1807. {
  1808. // No need to deserialize function body if scriptContext closed because we can't execute it.
  1809. // Bigger problem is the script engine might have released bytecode file mapping and we can't deserialize.
  1810. Assert(!m_scriptContext->IsClosed());
  1811. executionFunctionBody = ((DeferDeserializeFunctionInfo*) this)->Deserialize();
  1812. this->GetFunctionInfo()->SetFunctionProxy(executionFunctionBody);
  1813. Assert(executionFunctionBody->GetFunctionInfo()->HasBody());
  1814. Assert(executionFunctionBody != this);
  1815. }
  1816. return (ParseableFunctionInfo *)executionFunctionBody;
  1817. }
  1818. ScriptFunctionType * FunctionProxy::GetDeferredPrototypeType() const
  1819. {
  1820. return deferredPrototypeType;
  1821. }
  1822. ScriptFunctionType * FunctionProxy::EnsureDeferredPrototypeType()
  1823. {
  1824. Assert(this->GetFunctionInfo()->GetFunctionProxy() == this);
  1825. return deferredPrototypeType != nullptr ?
  1826. static_cast<ScriptFunctionType*>(deferredPrototypeType) : AllocDeferredPrototypeType();
  1827. }
  1828. ScriptFunctionType * FunctionProxy::AllocDeferredPrototypeType()
  1829. {
  1830. Assert(deferredPrototypeType == nullptr);
  1831. ScriptFunctionType * type = ScriptFunctionType::New(this, true);
  1832. deferredPrototypeType = type;
  1833. return type;
  1834. }
  1835. ScriptFunctionType * FunctionProxy::GetUndeferredFunctionType() const
  1836. {
  1837. return undeferredFunctionType;
  1838. }
  1839. void FunctionProxy::SetUndeferredFunctionType(ScriptFunctionType * type)
  1840. {
  1841. undeferredFunctionType = type;
  1842. }
  1843. ScriptFunctionType * FunctionProxy::GetCrossSiteDeferredFunctionType() const
  1844. {
  1845. return HasParseableInfo() ? GetParseableFunctionInfo()->GetCrossSiteDeferredFunctionType() : nullptr;
  1846. }
  1847. void FunctionProxy::SetCrossSiteDeferredFunctionType(ScriptFunctionType * type)
  1848. {
  1849. Assert(HasParseableInfo());
  1850. GetParseableFunctionInfo()->SetCrossSiteDeferredFunctionType(type);
  1851. }
  1852. ScriptFunctionType * FunctionProxy::GetCrossSiteUndeferredFunctionType() const
  1853. {
  1854. return HasParseableInfo() ? GetParseableFunctionInfo()->GetCrossSiteUndeferredFunctionType() : nullptr;
  1855. }
  1856. void FunctionProxy::SetCrossSiteUndeferredFunctionType(ScriptFunctionType * type)
  1857. {
  1858. Assert(HasParseableInfo());
  1859. GetParseableFunctionInfo()->SetCrossSiteUndeferredFunctionType(type);
  1860. }
  1861. JavascriptMethod FunctionProxy::GetDirectEntryPoint(ProxyEntryPointInfo* entryPoint) const
  1862. {
  1863. Assert(entryPoint->jsMethod != nullptr);
  1864. return entryPoint->jsMethod;
  1865. }
  1866. // Function object type list methods
  1867. FunctionProxy::FunctionTypeWeakRefList* FunctionProxy::GetFunctionObjectTypeList() const
  1868. {
  1869. return this->GetAuxPtr<AuxPointerType::FunctionObjectTypeList>();
  1870. }
  1871. void FunctionProxy::SetFunctionObjectTypeList(FunctionProxy::FunctionTypeWeakRefList* list)
  1872. {
  1873. this->SetAuxPtr<AuxPointerType::FunctionObjectTypeList>(list);
  1874. }
  1875. FunctionProxy::FunctionTypeWeakRefList* FunctionProxy::EnsureFunctionObjectTypeList()
  1876. {
  1877. FunctionTypeWeakRefList* functionObjectTypeList = this->GetFunctionObjectTypeList();
  1878. if (functionObjectTypeList == nullptr)
  1879. {
  1880. Recycler* recycler = this->GetScriptContext()->GetRecycler();
  1881. functionObjectTypeList = RecyclerNew(recycler, FunctionTypeWeakRefList, recycler);
  1882. this->SetFunctionObjectTypeList(functionObjectTypeList);
  1883. }
  1884. return functionObjectTypeList;
  1885. }
  1886. void FunctionProxy::RegisterFunctionObjectType(ScriptFunctionType* functionType)
  1887. {
  1888. FunctionTypeWeakRefList* typeList = EnsureFunctionObjectTypeList();
  1889. Assert(functionType != deferredPrototypeType && functionType != undeferredFunctionType);
  1890. Recycler * recycler = this->GetScriptContext()->GetRecycler();
  1891. FunctionTypeWeakRef* weakRef = recycler->CreateWeakReferenceHandle(functionType);
  1892. typeList->SetAtFirstFreeSpot(weakRef);
  1893. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Registered type 0x%p on function body %p, count = %d\n"), functionType, this, typeList->Count());
  1894. }
  1895. void DeferDeserializeFunctionInfo::SetDisplayName(const char16* displayName)
  1896. {
  1897. size_t len = wcslen(displayName);
  1898. if (len > UINT_MAX)
  1899. {
  1900. // Can't support display name that big
  1901. Js::Throw::OutOfMemory();
  1902. }
  1903. SetDisplayName(displayName, (uint)len, 0);
  1904. }
  1905. void DeferDeserializeFunctionInfo::SetDisplayName(const char16* pszDisplayName, uint displayNameLength, uint displayShortNameOffset, SetDisplayNameFlags flags /* default to None */)
  1906. {
  1907. this->m_displayNameLength = displayNameLength;
  1908. this->m_displayShortNameOffset = displayShortNameOffset;
  1909. this->m_displayNameIsRecyclerAllocated = FunctionProxy::SetDisplayName(pszDisplayName, &this->m_displayName, displayNameLength, m_scriptContext, flags);
  1910. }
  1911. LPCWSTR DeferDeserializeFunctionInfo::GetSourceInfo(int& lineNumber, int& columnNumber) const
  1912. {
  1913. // Read all the necessary information from the serialized byte code
  1914. int lineNumberField, columnNumberField;
  1915. bool m_isEval, m_isDynamicFunction;
  1916. ByteCodeSerializer::ReadSourceInfo(this, lineNumberField, columnNumberField, m_isEval, m_isDynamicFunction);
  1917. // Decode them
  1918. lineNumber = ComputeAbsoluteLineNumber(lineNumberField);
  1919. columnNumber = ComputeAbsoluteColumnNumber(lineNumberField, columnNumberField);
  1920. return Js::ParseableFunctionInfo::GetSourceName<SourceContextInfo*>(this->GetSourceContextInfo(), m_isEval, m_isDynamicFunction);
  1921. }
  1922. void DeferDeserializeFunctionInfo::Finalize(bool isShutdown)
  1923. {
  1924. __super::Finalize(isShutdown);
  1925. PERF_COUNTER_DEC(Code, DeferDeserializeFunctionProxy);
  1926. }
  1927. FunctionBody* DeferDeserializeFunctionInfo::Deserialize()
  1928. {
  1929. Assert(this->GetFunctionInfo()->GetFunctionProxy() == this);
  1930. FunctionBody * body = ByteCodeSerializer::DeserializeFunction(this->m_scriptContext, this);
  1931. this->SetLocalFunctionId(body->GetLocalFunctionId());
  1932. this->SetOriginalEntryPoint(body->GetOriginalEntryPoint());
  1933. this->Copy(body);
  1934. this->UpdateFunctionBodyImpl(body);
  1935. Assert(body->GetFunctionBody() == body);
  1936. return body;
  1937. }
  1938. //
  1939. // hrParse can be one of the following from deferred re-parse (check CompileScriptException::ProcessError):
  1940. // E_OUTOFMEMORY
  1941. // E_UNEXPECTED
  1942. // SCRIPT_E_RECORDED,
  1943. // with ei.scode: ERRnoMemory, VBSERR_OutOfStack, E_OUTOFMEMORY, E_FAIL, E_ABORT
  1944. // Any other ei.scode shouldn't appear in deferred re-parse.
  1945. //
  1946. // Map errors like OOM/SOE, return it and clean hrParse. Any other error remaining in hrParse is an internal error.
  1947. //
  1948. HRESULT ParseableFunctionInfo::MapDeferredReparseError(HRESULT& hrParse, const CompileScriptException& se)
  1949. {
  1950. HRESULT hrMapped = NO_ERROR;
  1951. switch (hrParse)
  1952. {
  1953. case E_OUTOFMEMORY:
  1954. hrMapped = E_OUTOFMEMORY;
  1955. break;
  1956. case SCRIPT_E_RECORDED:
  1957. switch (se.ei.scode)
  1958. {
  1959. case ERRnoMemory:
  1960. case E_OUTOFMEMORY:
  1961. case VBSERR_OutOfMemory:
  1962. hrMapped = E_OUTOFMEMORY;
  1963. break;
  1964. case VBSERR_OutOfStack:
  1965. hrMapped = VBSERR_OutOfStack;
  1966. break;
  1967. case JSERR_AsmJsCompileError:
  1968. hrMapped = JSERR_AsmJsCompileError;
  1969. break;
  1970. case E_ABORT:
  1971. hrMapped = E_ABORT;
  1972. break;
  1973. }
  1974. }
  1975. if (FAILED(hrMapped))
  1976. {
  1977. // If we have mapped error, clear hrParse. We'll throw error from hrMapped.
  1978. hrParse = NO_ERROR;
  1979. }
  1980. return hrMapped;
  1981. }
  1982. FunctionBody* ParseableFunctionInfo::Parse(ScriptFunction ** functionRef, bool isByteCodeDeserialization)
  1983. {
  1984. Assert(this == this->GetFunctionInfo()->GetFunctionProxy());
  1985. if (!IsDeferredParseFunction())
  1986. {
  1987. // If not deferredparsed, the functionBodyImpl and this will be the same, just return the current functionBody.
  1988. Assert(GetFunctionBody()->IsFunctionParsed());
  1989. return GetFunctionBody();
  1990. }
  1991. bool asmjsParseFailed = false;
  1992. BOOL fParsed = FALSE;
  1993. FunctionBody* returnFunctionBody = nullptr;
  1994. bool isDebugOrAsmJsReparse = false;
  1995. FunctionBody* funcBody = nullptr;
  1996. {
  1997. AutoRestoreFunctionInfo autoRestoreFunctionInfo(this, DefaultEntryThunk);
  1998. // If m_hasBeenParsed = true, one of the following things happened things happened:
  1999. // - We had multiple function objects which were all defer-parsed, but with the same function body and one of them
  2000. // got the body to be parsed before another was called
  2001. // - We are in debug mode and had our thunks switched to DeferParseThunk
  2002. // - This is an already parsed asm.js module, which has been invalidated at link time and must be reparsed as a non-asm.js function
  2003. if (!this->m_hasBeenParsed)
  2004. {
  2005. this->GetUtf8SourceInfo()->StopTrackingDeferredFunction(this->GetLocalFunctionId());
  2006. funcBody = FunctionBody::NewFromParseableFunctionInfo(this);
  2007. autoRestoreFunctionInfo.funcBody = funcBody;
  2008. PERF_COUNTER_DEC(Code, DeferredFunction);
  2009. if (!this->GetSourceContextInfo()->IsDynamic())
  2010. {
  2011. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d; Is Top Level: %s; Source Url: %s\n"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(), this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"), this->GetSourceContextInfo()->url);
  2012. }
  2013. else
  2014. {
  2015. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d\n; Is Top Level: %s;"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(), this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"));
  2016. }
  2017. if (!this->GetIsTopLevel() &&
  2018. !this->GetSourceContextInfo()->IsDynamic() &&
  2019. this->m_scriptContext->DoUndeferGlobalFunctions())
  2020. {
  2021. this->GetUtf8SourceInfo()->UndeferGlobalFunctions([this](const Utf8SourceInfo::DeferredFunctionsDictionary::EntryType& func)
  2022. {
  2023. Js::ParseableFunctionInfo *nextFunc = func.Value();
  2024. JavascriptExceptionObject* pExceptionObject = nullptr;
  2025. if (nextFunc != nullptr && this != nextFunc)
  2026. {
  2027. try
  2028. {
  2029. nextFunc->Parse();
  2030. }
  2031. catch (OutOfMemoryException) {}
  2032. catch (StackOverflowException) {}
  2033. catch (const Js::JavascriptException& err)
  2034. {
  2035. pExceptionObject = err.GetAndClear();
  2036. }
  2037. // Do not do anything with an OOM or SOE, returning true is fine, it will then be undeferred (or attempted to again when called)
  2038. if (pExceptionObject)
  2039. {
  2040. if (pExceptionObject != ThreadContext::GetContextForCurrentThread()->GetPendingOOMErrorObject() &&
  2041. pExceptionObject != ThreadContext::GetContextForCurrentThread()->GetPendingSOErrorObject())
  2042. {
  2043. JavascriptExceptionOperators::DoThrow(pExceptionObject, /*scriptContext*/nullptr);
  2044. }
  2045. }
  2046. }
  2047. return true;
  2048. });
  2049. }
  2050. }
  2051. else
  2052. {
  2053. bool isDebugReparse = m_scriptContext->IsScriptContextInSourceRundownOrDebugMode() && !this->GetUtf8SourceInfo()->GetIsLibraryCode();
  2054. bool isAsmJsReparse = m_isAsmjsMode && !isDebugReparse;
  2055. isDebugOrAsmJsReparse = isAsmJsReparse || isDebugReparse;
  2056. funcBody = this->GetFunctionBody();
  2057. // As we have a valid function body already clear the restore data
  2058. autoRestoreFunctionInfo.Clear();
  2059. if (isDebugOrAsmJsReparse)
  2060. {
  2061. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2062. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2063. #endif
  2064. #if DBG
  2065. Assert(
  2066. funcBody->IsReparsed()
  2067. || m_scriptContext->IsScriptContextInSourceRundownOrDebugMode()
  2068. || m_isAsmjsMode);
  2069. #endif
  2070. OUTPUT_TRACE(Js::DebuggerPhase, _u("Full nested reparse of function: %s (%s)\n"), funcBody->GetDisplayName(), funcBody->GetDebugNumberSet(debugStringBuffer));
  2071. if (funcBody->GetByteCode())
  2072. {
  2073. // The current function needs to be cleaned up before getting generated in the debug mode.
  2074. funcBody->CleanupToReparse();
  2075. }
  2076. }
  2077. }
  2078. // Note that we may be trying to re-gen an already-completed function. (This can happen, for instance,
  2079. // in the case of named function expressions inside "with" statements in compat mode.)
  2080. // In such a case, there's no work to do.
  2081. if (funcBody->GetByteCode() == nullptr)
  2082. {
  2083. #if ENABLE_PROFILE_INFO
  2084. Assert(!funcBody->HasExecutionDynamicProfileInfo());
  2085. #endif
  2086. // In debug or asm.js mode, the scriptlet will be asked to recompile again.
  2087. HRESULT hr = NO_ERROR;
  2088. HRESULT hrParser = NO_ERROR;
  2089. HRESULT hrParseCodeGen = NO_ERROR;
  2090. BEGIN_LEAVE_SCRIPT_INTERNAL(m_scriptContext)
  2091. {
  2092. bool isCesu8 = m_scriptContext->GetSource(funcBody->GetSourceIndex())->IsCesu8();
  2093. size_t offset = this->StartOffset();
  2094. charcount_t charOffset = this->StartInDocument();
  2095. size_t length = this->LengthInBytes();
  2096. LPCUTF8 pszStart = this->GetStartOfDocument();
  2097. uint32 grfscr = funcBody->GetGrfscr() | fscrDeferredFnc;
  2098. // For the global function we want to re-use the glo functionbody which is already created in the non-debug mode
  2099. if (!funcBody->GetIsGlobalFunc())
  2100. {
  2101. grfscr &= ~fscrGlobalCode;
  2102. }
  2103. if (!funcBody->GetIsDeclaration() && !funcBody->GetIsGlobalFunc()) // No refresh may reparse global function (e.g. eval code)
  2104. {
  2105. // Notify the parser that the top-level function was defined in an expression,
  2106. // (not a function declaration statement).
  2107. grfscr |= fscrDeferredFncExpression;
  2108. }
  2109. if (funcBody->IsMethod())
  2110. {
  2111. grfscr |= fscrDeferredFncIsMethod;
  2112. }
  2113. else
  2114. {
  2115. grfscr &= ~fscrDeferredFncIsMethod;
  2116. }
  2117. if (funcBody->IsAsync())
  2118. {
  2119. grfscr |= fscrDeferredFncIsAsync;
  2120. }
  2121. else
  2122. {
  2123. grfscr &= ~fscrDeferredFncIsAsync;
  2124. }
  2125. if (funcBody->IsGenerator())
  2126. {
  2127. grfscr |= fscrDeferredFncIsGenerator;
  2128. }
  2129. else
  2130. {
  2131. grfscr &= ~fscrDeferredFncIsGenerator;
  2132. }
  2133. if (isDebugOrAsmJsReparse)
  2134. {
  2135. // Disable deferred parsing if not DeferNested, or doing a debug/asm.js re-parse
  2136. // Disable asm.js when debugging or if linking failed
  2137. // Disable parser state cache if we're debugging or reparsing asm.js
  2138. grfscr = fscrNoAsmJs | (grfscr & ~(fscrWillDeferFncParse | fscrCreateParserState));
  2139. }
  2140. BEGIN_TRANSLATE_EXCEPTION_TO_HRESULT
  2141. {
  2142. CompileScriptException se;
  2143. Parser ps(m_scriptContext, funcBody->GetIsStrictMode() ? TRUE : FALSE);
  2144. ParseNodeProg * parseTree = nullptr;
  2145. uint nextFunctionId = funcBody->GetLocalFunctionId();
  2146. hrParser = ps.ParseSourceWithOffset(&parseTree, pszStart, offset, length, charOffset, isCesu8, grfscr, &se,
  2147. &nextFunctionId, funcBody->GetRelativeLineNumber(), funcBody->GetSourceContextInfo(),
  2148. funcBody);
  2149. // Assert(FAILED(hrParser) || nextFunctionId == funcBody->deferredParseNextFunctionId || isDebugOrAsmJsReparse || isByteCodeDeserialization);
  2150. if (FAILED(hrParser))
  2151. {
  2152. hrParseCodeGen = MapDeferredReparseError(hrParser, se); // Map certain errors like OOM/SOE
  2153. AssertMsg(hrParseCodeGen == JSERR_AsmJsCompileError // AsmJsCompileError is not a syntax error
  2154. || (FAILED(hrParseCodeGen) && SUCCEEDED(hrParser)), "Syntax errors should never be detected on deferred re-parse");
  2155. }
  2156. else
  2157. {
  2158. TRACE_BYTECODE(_u("\nDeferred parse %s\n"), funcBody->GetDisplayName());
  2159. Js::AutoDynamicCodeReference dynamicFunctionReference(m_scriptContext);
  2160. bool forceNoNative = isDebugOrAsmJsReparse ? this->GetScriptContext()->IsInterpreted() : false;
  2161. ParseableFunctionInfo* rootFunc = funcBody->GetParseableFunctionInfo();
  2162. hrParseCodeGen = GenerateByteCode(parseTree, grfscr, m_scriptContext,
  2163. &rootFunc, funcBody->GetSourceIndex(),
  2164. forceNoNative, &ps, &se, funcBody->GetScopeInfo(), functionRef);
  2165. funcBody->SetParseableFunctionInfo(rootFunc);
  2166. if (SUCCEEDED(hrParseCodeGen))
  2167. {
  2168. fParsed = TRUE;
  2169. }
  2170. else
  2171. {
  2172. Assert(hrParseCodeGen == SCRIPT_E_RECORDED);
  2173. hrParseCodeGen = se.ei.scode;
  2174. }
  2175. }
  2176. }
  2177. END_TRANSLATE_EXCEPTION_TO_HRESULT(hr);
  2178. }
  2179. END_LEAVE_SCRIPT_INTERNAL(m_scriptContext);
  2180. THROW_KNOWN_HRESULT_EXCEPTIONS(hr, m_scriptContext);
  2181. Assert(hr == NO_ERROR);
  2182. if (!SUCCEEDED(hrParser))
  2183. {
  2184. JavascriptError::ThrowError(m_scriptContext, VBSERR_InternalError);
  2185. }
  2186. else if (!SUCCEEDED(hrParseCodeGen))
  2187. {
  2188. /*
  2189. * VBSERR_OutOfStack is of type kjstError but we throw a (more specific) StackOverflowError when a hard stack
  2190. * overflow occurs. To keep the behavior consistent I'm special casing it here.
  2191. */
  2192. if (hrParseCodeGen == VBSERR_OutOfStack)
  2193. {
  2194. JavascriptError::ThrowStackOverflowError(m_scriptContext);
  2195. }
  2196. else if (hrParseCodeGen == JSERR_AsmJsCompileError)
  2197. {
  2198. asmjsParseFailed = true;
  2199. }
  2200. else
  2201. {
  2202. JavascriptError::MapAndThrowError(m_scriptContext, hrParseCodeGen);
  2203. }
  2204. }
  2205. }
  2206. else
  2207. {
  2208. fParsed = FALSE;
  2209. }
  2210. if (!asmjsParseFailed)
  2211. {
  2212. autoRestoreFunctionInfo.Clear();
  2213. }
  2214. }
  2215. if (fParsed == TRUE)
  2216. {
  2217. // Restore if the function has nameIdentifier reference, as that name on the left side will not be parsed again while deferparse.
  2218. funcBody->SetIsNameIdentifierRef(this->GetIsNameIdentifierRef());
  2219. this->m_hasBeenParsed = true;
  2220. returnFunctionBody = funcBody;
  2221. }
  2222. else if(!asmjsParseFailed)
  2223. {
  2224. returnFunctionBody = this->GetFunctionBody();
  2225. }
  2226. if (asmjsParseFailed)
  2227. {
  2228. // disable asm.js and reparse on failure
  2229. m_grfscr |= fscrNoAsmJs;
  2230. return Parse(functionRef, isByteCodeDeserialization);
  2231. }
  2232. return returnFunctionBody;
  2233. }
  2234. #ifdef ASMJS_PLAT
  2235. FunctionBody* ParseableFunctionInfo::ParseAsmJs(Parser * ps, __out CompileScriptException * se, __out ParseNodeProg ** parseTree)
  2236. {
  2237. Assert(IsDeferredParseFunction());
  2238. Assert(m_isAsmjsMode);
  2239. FunctionBody* returnFunctionBody = nullptr;
  2240. FunctionBody* funcBody = nullptr;
  2241. funcBody = FunctionBody::NewFromRecycler(
  2242. this->m_scriptContext,
  2243. this->m_displayName,
  2244. this->m_displayNameLength,
  2245. this->m_displayShortNameOffset,
  2246. this->GetNestedCount(),
  2247. this->GetUtf8SourceInfo(),
  2248. this->m_functionNumber,
  2249. this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId,
  2250. this->GetLocalFunctionId(),
  2251. (FunctionInfo::Attributes)(this->GetAttributes() & ~(FunctionInfo::Attributes::DeferredDeserialize | FunctionInfo::Attributes::DeferredParse)),
  2252. Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue
  2253. #ifdef PERF_COUNTERS
  2254. , false /* is function from deferred deserialized proxy */
  2255. #endif
  2256. );
  2257. this->Copy(funcBody);
  2258. PERF_COUNTER_DEC(Code, DeferredFunction);
  2259. if (!this->GetSourceContextInfo()->IsDynamic())
  2260. {
  2261. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d; Is Top Level: %s; Source Url: %s\n"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(), this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"), this->GetSourceContextInfo()->url);
  2262. }
  2263. else
  2264. {
  2265. PHASE_PRINT_TESTTRACE1(Js::DeferParsePhase, _u("TestTrace: Deferred function parsed - ID: %d; Display Name: %s; Length: %d; Nested Function Count: %d; Utf8SourceInfo: %d; Source Length: %d\n; Is Top Level: %s;"), m_functionNumber, this->GetDisplayName(), this->m_cchLength, this->GetNestedCount(), this->m_utf8SourceInfo->GetSourceInfoId(), this->m_utf8SourceInfo->GetCchLength(), this->GetIsTopLevel() ? _u("True") : _u("False"));
  2266. }
  2267. #if ENABLE_PROFILE_INFO
  2268. Assert(!funcBody->HasExecutionDynamicProfileInfo());
  2269. #endif
  2270. HRESULT hrParser = NO_ERROR;
  2271. HRESULT hrParseCodeGen = NO_ERROR;
  2272. bool isCesu8 = m_scriptContext->GetSource(funcBody->GetSourceIndex())->IsCesu8();
  2273. size_t offset = this->StartOffset();
  2274. charcount_t charOffset = this->StartInDocument();
  2275. size_t length = this->LengthInBytes();
  2276. LPCUTF8 pszStart = this->GetStartOfDocument();
  2277. uint32 grfscr = funcBody->GetGrfscr() | fscrDeferredFnc | fscrDeferredFncExpression;
  2278. uint nextFunctionId = funcBody->GetLocalFunctionId();
  2279. // if parser throws, it will be caught by function trying to bytecode gen the asm.js module, so don't need to catch/rethrow here
  2280. hrParser = ps->ParseSourceWithOffset(parseTree, pszStart, offset, length, charOffset, isCesu8, grfscr, se,
  2281. &nextFunctionId, funcBody->GetRelativeLineNumber(), funcBody->GetSourceContextInfo(),
  2282. funcBody);
  2283. Assert(FAILED(hrParser) || funcBody->deferredParseNextFunctionId == nextFunctionId);
  2284. if (FAILED(hrParser))
  2285. {
  2286. hrParseCodeGen = MapDeferredReparseError(hrParser, *se); // Map certain errors like OOM/SOE
  2287. AssertMsg(FAILED(hrParseCodeGen) && SUCCEEDED(hrParser), "Syntax errors should never be detected on deferred re-parse");
  2288. }
  2289. if (!SUCCEEDED(hrParser))
  2290. {
  2291. Throw::InternalError();
  2292. }
  2293. else if (!SUCCEEDED(hrParseCodeGen))
  2294. {
  2295. if (hrParseCodeGen == VBSERR_OutOfStack)
  2296. {
  2297. Throw::StackOverflow(m_scriptContext, nullptr);
  2298. }
  2299. else
  2300. {
  2301. Assert(hrParseCodeGen == E_OUTOFMEMORY);
  2302. Throw::OutOfMemory();
  2303. }
  2304. }
  2305. UpdateFunctionBodyImpl(funcBody);
  2306. m_hasBeenParsed = true;
  2307. Assert(funcBody->GetFunctionBody() == funcBody);
  2308. returnFunctionBody = funcBody;
  2309. return returnFunctionBody;
  2310. }
  2311. #endif
  2312. void ParseableFunctionInfo::Finalize(bool isShutdown)
  2313. {
  2314. __super::Finalize(isShutdown);
  2315. if (this->GetFunctionInfo())
  2316. {
  2317. // (If function info was never set, then initialization didn't finish, so there's nothing to remove from the dictionary.)
  2318. this->GetUtf8SourceInfo()->StopTrackingDeferredFunction(this->GetLocalFunctionId());
  2319. }
  2320. if (!this->m_hasBeenParsed)
  2321. {
  2322. PERF_COUNTER_DEC(Code, DeferredFunction);
  2323. }
  2324. }
  2325. bool ParseableFunctionInfo::IsFakeGlobalFunc(uint32 flags) const
  2326. {
  2327. return GetIsGlobalFunc() && !(flags & fscrGlobalCode);
  2328. }
  2329. #ifdef NTBUILD
  2330. bool ParseableFunctionInfo::GetExternalDisplaySourceName(BSTR* sourceName)
  2331. {
  2332. Assert(sourceName);
  2333. if (IsDynamicScript() && GetUtf8SourceInfo()->GetDebugDocumentName(sourceName))
  2334. {
  2335. return true;
  2336. }
  2337. *sourceName = ::SysAllocString(GetSourceName());
  2338. return *sourceName != nullptr;
  2339. }
  2340. #endif
  2341. const char16* FunctionProxy::WrapWithBrackets(const char16* name, charcount_t sz, ScriptContext* scriptContext)
  2342. {
  2343. char16 * wrappedName = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, sz + 3); //[]\0
  2344. wrappedName[0] = _u('[');
  2345. char16 *next = wrappedName;
  2346. js_wmemcpy_s(++next, sz, name, sz);
  2347. wrappedName[sz + 1] = _u(']');
  2348. wrappedName[sz + 2] = _u('\0');
  2349. return wrappedName;
  2350. }
  2351. const char16* FunctionProxy::GetShortDisplayName(charcount_t * shortNameLength)
  2352. {
  2353. const char16* name = this->GetDisplayName();
  2354. uint nameLength = this->GetDisplayNameLength();
  2355. if (name == nullptr)
  2356. {
  2357. *shortNameLength = 0;
  2358. return Constants::Empty;
  2359. }
  2360. if (IsConstantFunctionName(name))
  2361. {
  2362. *shortNameLength = nameLength;
  2363. return name;
  2364. }
  2365. uint shortNameOffset = this->GetShortDisplayNameOffset();
  2366. const char16 * shortName = name + shortNameOffset;
  2367. bool isBracketCase = shortNameOffset != 0 && name[shortNameOffset-1] == '[';
  2368. Assert(nameLength >= shortNameOffset);
  2369. *shortNameLength = nameLength - shortNameOffset;
  2370. if (!isBracketCase)
  2371. {
  2372. return shortName;
  2373. }
  2374. Assert(name[nameLength - 1] == ']');
  2375. char16 * finalshorterName = RecyclerNewArrayLeaf(this->GetScriptContext()->GetRecycler(), char16, *shortNameLength);
  2376. js_wmemcpy_s(finalshorterName, *shortNameLength, shortName, *shortNameLength - 1); // we don't want the last character in shorterName
  2377. finalshorterName[*shortNameLength - 1] = _u('\0');
  2378. *shortNameLength = *shortNameLength - 1;
  2379. return finalshorterName;
  2380. }
  2381. /*static*/
  2382. bool FunctionProxy::IsConstantFunctionName(const char16* srcName)
  2383. {
  2384. if (srcName == Js::Constants::GlobalFunction ||
  2385. srcName == Js::Constants::AnonymousFunction ||
  2386. srcName == Js::Constants::GlobalCode ||
  2387. srcName == Js::Constants::Anonymous ||
  2388. srcName == Js::Constants::UnknownScriptCode ||
  2389. srcName == Js::Constants::FunctionCode)
  2390. {
  2391. return true;
  2392. }
  2393. return false;
  2394. }
  2395. /*static */
  2396. /*Return value: Whether the target value is a recycler pointer or not*/
  2397. bool FunctionProxy::SetDisplayName(const char16* srcName, const char16** destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags /* default to None */)
  2398. {
  2399. Assert(destName);
  2400. Assert(scriptContext);
  2401. if (srcName == nullptr)
  2402. {
  2403. *destName = (_u(""));
  2404. return false;
  2405. }
  2406. else if (IsConstantFunctionName(srcName) || (flags & SetDisplayNameFlagsDontCopy) != 0)
  2407. {
  2408. *destName = srcName;
  2409. return (flags & SetDisplayNameFlagsRecyclerAllocated) != 0; // Return true if array is recycler allocated
  2410. }
  2411. else
  2412. {
  2413. uint numCharacters = displayNameLength + 1;
  2414. Assert((flags & SetDisplayNameFlagsDontCopy) == 0);
  2415. *destName = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), char16, numCharacters);
  2416. js_wmemcpy_s((char16 *)*destName, numCharacters, srcName, numCharacters);
  2417. ((char16 *)(*destName))[numCharacters - 1] = _u('\0');
  2418. return true;
  2419. }
  2420. }
  2421. bool FunctionProxy::SetDisplayName(const char16* srcName, WriteBarrierPtr<const char16>* destName, uint displayNameLength, ScriptContext * scriptContext, SetDisplayNameFlags flags /* default to None */)
  2422. {
  2423. const char16* dest = nullptr;
  2424. bool targetIsRecyclerMemory = SetDisplayName(srcName, &dest, displayNameLength, scriptContext, flags);
  2425. if (targetIsRecyclerMemory)
  2426. {
  2427. *destName = dest;
  2428. }
  2429. else
  2430. {
  2431. destName->NoWriteBarrierSet(dest);
  2432. }
  2433. return targetIsRecyclerMemory;
  2434. }
  2435. void ParseableFunctionInfo::SetDisplayName(const char16* pszDisplayName)
  2436. {
  2437. size_t len = wcslen(pszDisplayName);
  2438. if (len > UINT_MAX)
  2439. {
  2440. // Can't support display name that big
  2441. Js::Throw::OutOfMemory();
  2442. }
  2443. SetDisplayName(pszDisplayName, (uint)len, 0);
  2444. }
  2445. void ParseableFunctionInfo::SetDisplayName(const char16* pszDisplayName, uint displayNameLength, uint displayShortNameOffset, SetDisplayNameFlags flags /* default to None */)
  2446. {
  2447. this->m_displayNameLength = displayNameLength;
  2448. this->m_displayShortNameOffset = displayShortNameOffset;
  2449. this->m_displayNameIsRecyclerAllocated = FunctionProxy::SetDisplayName(pszDisplayName, &this->m_displayName, displayNameLength, m_scriptContext, flags);
  2450. }
  2451. // SourceInfo methods
  2452. /* static */
  2453. template <typename TStatementMapList>
  2454. FunctionBody::StatementMap * FunctionBody::GetNextNonSubexpressionStatementMap(TStatementMapList *statementMapList, int & startingAtIndex)
  2455. {
  2456. AssertMsg(statementMapList != nullptr, "Must have valid statementMapList to execute");
  2457. FunctionBody::StatementMap *map = statementMapList->Item(startingAtIndex);
  2458. while (map->isSubexpression && startingAtIndex < statementMapList->Count() - 1)
  2459. {
  2460. map = statementMapList->Item(++startingAtIndex);
  2461. }
  2462. if (map->isSubexpression) // Didn't find any non inner maps
  2463. {
  2464. return nullptr;
  2465. }
  2466. return map;
  2467. }
  2468. // explicitly instantiate template
  2469. template FunctionBody::StatementMap *
  2470. FunctionBody::GetNextNonSubexpressionStatementMap<FunctionBody::ArenaStatementMapList>(FunctionBody::ArenaStatementMapList *statementMapList, int & startingAtIndex);
  2471. template FunctionBody::StatementMap *
  2472. FunctionBody::GetNextNonSubexpressionStatementMap<FunctionBody::StatementMapList>(FunctionBody::StatementMapList *statementMapList, int & startingAtIndex);
  2473. /* static */ FunctionBody::StatementMap * FunctionBody::GetPrevNonSubexpressionStatementMap(StatementMapList *statementMapList, int & startingAtIndex)
  2474. {
  2475. AssertMsg(statementMapList != nullptr, "Must have valid statementMapList to execute");
  2476. StatementMap *map = statementMapList->Item(startingAtIndex);
  2477. while (startingAtIndex && map->isSubexpression)
  2478. {
  2479. map = statementMapList->Item(--startingAtIndex);
  2480. }
  2481. if (map->isSubexpression) // Didn't find any non inner maps
  2482. {
  2483. return nullptr;
  2484. }
  2485. return map;
  2486. }
  2487. void ParseableFunctionInfo::SetSourceInfo(uint sourceIndex, ParseNodeFnc * node, bool isEval, bool isDynamicFunction)
  2488. {
  2489. if (!m_utf8SourceHasBeenSet)
  2490. {
  2491. this->m_sourceIndex = sourceIndex;
  2492. this->m_cchStartOffset = node->ichMin;
  2493. this->m_cchLength = node->LengthInCodepoints();
  2494. this->m_lineNumber = node->lineNumber;
  2495. this->m_columnNumber = node->columnNumber;
  2496. this->m_isEval = isEval;
  2497. this->m_isDynamicFunction = isDynamicFunction;
  2498. // It would have been better if we detect and reject large source buffer earlier before parsing
  2499. size_t cbMin = node->cbMin;
  2500. size_t lengthInBytes = node->LengthInBytes();
  2501. if (cbMin > UINT_MAX || lengthInBytes > UINT_MAX)
  2502. {
  2503. Js::Throw::OutOfMemory();
  2504. }
  2505. Assert(node->cbStringMin <= node->cbMin);
  2506. this->m_cbStartOffset = (uint)cbMin;
  2507. this->m_cbStartPrintOffset = (uint)node->cbStringMin;
  2508. this->m_cbLength = (uint)lengthInBytes;
  2509. Assert(this->m_utf8SourceInfo != nullptr);
  2510. this->m_utf8SourceHasBeenSet = true;
  2511. if (this->IsFunctionBody())
  2512. {
  2513. this->GetFunctionBody()->FinishSourceInfo();
  2514. }
  2515. }
  2516. #if DBG
  2517. else
  2518. {
  2519. AssertMsg(this->m_sourceIndex == sourceIndex, "Mismatched source index");
  2520. if (!this->GetIsGlobalFunc())
  2521. {
  2522. // In the global function case with a @cc_on, we modify some of these values so it might
  2523. // not match on reparse (see ParseableFunctionInfo::Parse()).
  2524. AssertMsg(this->StartOffset() == node->cbMin, "Mismatched source start offset");
  2525. AssertMsg(this->m_cchStartOffset == node->ichMin, "Mismatched source character start offset");
  2526. AssertMsg(this->m_cchLength == node->LengthInCodepoints(), "Mismatched source length");
  2527. AssertMsg(this->LengthInBytes() == node->LengthInBytes(), "Mismatched source encoded byte length");
  2528. }
  2529. AssertMsg(this->m_isEval == isEval, "Mismatched source type");
  2530. AssertMsg(this->m_isDynamicFunction == isDynamicFunction, "Mismatch source type");
  2531. }
  2532. #endif
  2533. #if DBG_DUMP
  2534. if (PHASE_TRACE1(Js::FunctionSourceInfoParsePhase))
  2535. {
  2536. Assert(this->GetFunctionInfo()->HasBody());
  2537. if (this->IsFunctionBody())
  2538. {
  2539. FunctionBody* functionBody = this->GetFunctionBody();
  2540. Assert( functionBody != nullptr );
  2541. functionBody->PrintStatementSourceLineFromStartOffset(functionBody->StartInDocument());
  2542. Output::Flush();
  2543. }
  2544. }
  2545. #endif
  2546. }
  2547. void ParseableFunctionInfo::SetSourceInfo(uint sourceIndex)
  2548. {
  2549. // TODO (michhol): how do we want to handle wasm source?
  2550. if (!m_utf8SourceHasBeenSet)
  2551. {
  2552. this->m_sourceIndex = sourceIndex;
  2553. this->m_cchStartOffset = 0;
  2554. this->m_cchLength = 0;
  2555. this->m_lineNumber = 0;
  2556. this->m_columnNumber = 0;
  2557. this->m_cbStartOffset = 0;
  2558. this->m_cbStartPrintOffset = 0;
  2559. this->m_cbLength = 0;
  2560. this->m_utf8SourceHasBeenSet = true;
  2561. if (this->IsFunctionBody())
  2562. {
  2563. this->GetFunctionBody()->FinishSourceInfo();
  2564. }
  2565. }
  2566. #if DBG
  2567. else
  2568. {
  2569. AssertMsg(this->m_sourceIndex == sourceIndex, "Mismatched source index");
  2570. }
  2571. #endif
  2572. }
  2573. bool FunctionBody::Is(void* ptr)
  2574. {
  2575. if(!ptr)
  2576. {
  2577. return false;
  2578. }
  2579. return VirtualTableInfo<FunctionBody>::HasVirtualTable(ptr);
  2580. }
  2581. bool FunctionBody::HasLineBreak() const
  2582. {
  2583. return this->HasLineBreak(this->StartOffset(), this->m_cchStartOffset + this->m_cchLength);
  2584. }
  2585. bool FunctionBody::HasLineBreak(charcount_t start, charcount_t end) const
  2586. {
  2587. if (start > end) return false;
  2588. charcount_t cchLength = end - start;
  2589. if (start < this->m_cchStartOffset || cchLength > this->m_cchLength) return false;
  2590. LPCUTF8 src = this->GetSource(_u("FunctionBody::HasLineBreak"));
  2591. LPCUTF8 last = src + this->LengthInBytes();
  2592. size_t offset = this->LengthInBytes() == this->m_cchLength ?
  2593. start - this->m_cchStartOffset :
  2594. utf8::CharacterIndexToByteIndex(src, this->LengthInBytes(), start - this->m_cchStartOffset, utf8::doAllowThreeByteSurrogates);
  2595. src = src + offset;
  2596. utf8::DecodeOptions options = utf8::doAllowThreeByteSurrogates;
  2597. for (charcount_t cch = cchLength; cch > 0; --cch)
  2598. {
  2599. switch (utf8::Decode(src, last, options))
  2600. {
  2601. case '\r':
  2602. case '\n':
  2603. case 0x2028:
  2604. case 0x2029:
  2605. return true;
  2606. }
  2607. }
  2608. return false;
  2609. }
  2610. FunctionBody::StatementMap* FunctionBody::GetMatchingStatementMapFromByteCode(int byteCodeOffset, bool ignoreSubexpressions /* = false */)
  2611. {
  2612. StatementMapList * pStatementMaps = this->GetStatementMaps();
  2613. if (pStatementMaps)
  2614. {
  2615. Assert(m_sourceInfo.pSpanSequence == nullptr);
  2616. for (int index = 0; index < pStatementMaps->Count(); index++)
  2617. {
  2618. FunctionBody::StatementMap* pStatementMap = pStatementMaps->Item(index);
  2619. if (!(ignoreSubexpressions && pStatementMap->isSubexpression) && pStatementMap->byteCodeSpan.Includes(byteCodeOffset))
  2620. {
  2621. return pStatementMap;
  2622. }
  2623. }
  2624. }
  2625. return nullptr;
  2626. }
  2627. // Returns the StatementMap for the offset.
  2628. // 1. Current statementMap if bytecodeoffset falls within bytecode's span
  2629. // 2. Previous if the bytecodeoffset is in between previous's end to current's begin
  2630. FunctionBody::StatementMap* FunctionBody::GetEnclosingStatementMapFromByteCode(int byteCodeOffset, bool ignoreSubexpressions /* = false */)
  2631. {
  2632. int index = GetEnclosingStatementIndexFromByteCode(byteCodeOffset, ignoreSubexpressions);
  2633. if (index != -1)
  2634. {
  2635. return this->GetStatementMaps()->Item(index);
  2636. }
  2637. return nullptr;
  2638. }
  2639. // Returns the index of StatementMap for
  2640. // 1. Current statementMap if bytecodeoffset falls within bytecode's span
  2641. // 2. Previous if the bytecodeoffset is in between previous's end to current's begin
  2642. // 3. -1 of the failures.
  2643. int FunctionBody::GetEnclosingStatementIndexFromByteCode(int byteCodeOffset, bool ignoreSubexpressions /* = false */)
  2644. {
  2645. StatementMapList * pStatementMaps = this->GetStatementMaps();
  2646. if (pStatementMaps == nullptr)
  2647. {
  2648. // e.g. internal library.
  2649. return -1;
  2650. }
  2651. Assert(m_sourceInfo.pSpanSequence == nullptr);
  2652. for (int index = 0; index < pStatementMaps->Count(); index++)
  2653. {
  2654. FunctionBody::StatementMap* pStatementMap = pStatementMaps->Item(index);
  2655. if (!(ignoreSubexpressions && pStatementMap->isSubexpression) && pStatementMap->byteCodeSpan.Includes(byteCodeOffset))
  2656. {
  2657. return index;
  2658. }
  2659. else if (!pStatementMap->isSubexpression && byteCodeOffset < pStatementMap->byteCodeSpan.begin) // We always ignore sub expressions when checking if we went too far
  2660. {
  2661. return index > 0 ? index - 1 : 0;
  2662. }
  2663. }
  2664. return pStatementMaps->Count() - 1;
  2665. }
  2666. // In some cases in legacy mode, due to the state scriptContext->windowIdList, the parser might not detect an eval call in the first parse but do so in the reparse
  2667. // This fixes up the state at the start of reparse
  2668. void FunctionBody::SaveState(ParseNodeFnc * pnodeFnc)
  2669. {
  2670. Assert(!this->IsReparsed());
  2671. this->SetChildCallsEval(!!pnodeFnc->ChildCallsEval());
  2672. this->SetCallsEval(!!pnodeFnc->CallsEval());
  2673. this->SetHasReferenceableBuiltInArguments(!!pnodeFnc->HasReferenceableBuiltInArguments());
  2674. }
  2675. void FunctionBody::RestoreState(ParseNodeFnc * pnodeFnc)
  2676. {
  2677. Assert(this->IsReparsed());
  2678. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2679. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2680. #endif
  2681. if(!!pnodeFnc->ChildCallsEval() != this->GetChildCallsEval())
  2682. {
  2683. OUTPUT_VERBOSE_TRACE(Js::DebuggerPhase, _u("Child calls eval is different on debug reparse: %s(%s)\n"), this->GetExternalDisplayName(), this->GetDebugNumberSet(debugStringBuffer));
  2684. }
  2685. if(!!pnodeFnc->CallsEval() != this->GetCallsEval())
  2686. {
  2687. OUTPUT_VERBOSE_TRACE(Js::DebuggerPhase, _u("Calls eval is different on debug reparse: %s(%s)\n"), this->GetExternalDisplayName(), this->GetDebugNumberSet(debugStringBuffer));
  2688. }
  2689. if(!!pnodeFnc->HasReferenceableBuiltInArguments() != this->HasReferenceableBuiltInArguments())
  2690. {
  2691. OUTPUT_VERBOSE_TRACE(Js::DebuggerPhase, _u("Referenceable Built in args is different on debug reparse: %s(%s)\n"), this->GetExternalDisplayName(), this->GetDebugNumberSet(debugStringBuffer));
  2692. }
  2693. pnodeFnc->SetChildCallsEval(this->GetChildCallsEval());
  2694. pnodeFnc->SetCallsEval(this->GetCallsEval());
  2695. pnodeFnc->SetHasReferenceableBuiltInArguments(this->HasReferenceableBuiltInArguments());
  2696. }
  2697. // Retrieves statement map for given byte code offset.
  2698. // Parameters:
  2699. // - sourceOffset: byte code offset to get map for.
  2700. // - mapIndex: if not NULL, receives the index of found map.
  2701. FunctionBody::StatementMap* FunctionBody::GetMatchingStatementMapFromSource(int sourceOffset, int* pMapIndex /* = nullptr */)
  2702. {
  2703. StatementMapList * pStatementMaps = this->GetStatementMaps();
  2704. if (pStatementMaps && pStatementMaps->Count() > 0)
  2705. {
  2706. Assert(m_sourceInfo.pSpanSequence == nullptr);
  2707. for (int index = pStatementMaps->Count() - 1; index >= 0; index--)
  2708. {
  2709. FunctionBody::StatementMap* pStatementMap = pStatementMaps->Item(index);
  2710. if (!pStatementMap->isSubexpression && pStatementMap->sourceSpan.Includes(sourceOffset))
  2711. {
  2712. if (pMapIndex)
  2713. {
  2714. *pMapIndex = index;
  2715. }
  2716. return pStatementMap;
  2717. }
  2718. }
  2719. }
  2720. if (pMapIndex)
  2721. {
  2722. *pMapIndex = 0;
  2723. }
  2724. return nullptr;
  2725. }
  2726. //
  2727. // The function determine the line and column for a bytecode offset within the current script buffer.
  2728. //
  2729. bool FunctionBody::GetLineCharOffset(int byteCodeOffset, ULONG* _line, LONG* _charOffset, bool canAllocateLineCache /*= true*/)
  2730. {
  2731. Assert(!this->GetUtf8SourceInfo()->GetIsLibraryCode());
  2732. int startCharOfStatement = this->m_cchStartOffset; // Default to the start of this function
  2733. if (m_sourceInfo.pSpanSequence)
  2734. {
  2735. SmallSpanSequenceIter iter;
  2736. m_sourceInfo.pSpanSequence->Reset(iter);
  2737. StatementData data;
  2738. if (m_sourceInfo.pSpanSequence->GetMatchingStatementFromBytecode(byteCodeOffset, iter, data)
  2739. && EndsAfter(data.sourceBegin))
  2740. {
  2741. startCharOfStatement = data.sourceBegin;
  2742. }
  2743. }
  2744. else
  2745. {
  2746. Js::FunctionBody::StatementMap* map = this->GetEnclosingStatementMapFromByteCode(byteCodeOffset, false);
  2747. if (map && EndsAfter(map->sourceSpan.begin))
  2748. {
  2749. startCharOfStatement = map->sourceSpan.begin;
  2750. }
  2751. }
  2752. return this->GetLineCharOffsetFromStartChar(startCharOfStatement, _line, _charOffset, canAllocateLineCache);
  2753. }
  2754. bool FunctionBody::GetLineCharOffsetFromStartChar(int startCharOfStatement, ULONG* _line, LONG* _charOffset, bool canAllocateLineCache /*= true*/)
  2755. {
  2756. Assert(!this->GetUtf8SourceInfo()->GetIsLibraryCode() || this->IsJsBuiltInCode());
  2757. // The following adjusts for where the script is within the document
  2758. ULONG line = this->GetHostStartLine();
  2759. charcount_t column = 0;
  2760. ULONG lineCharOffset = 0;
  2761. charcount_t lineByteOffset = 0;
  2762. if (startCharOfStatement > 0)
  2763. {
  2764. bool doSlowLookup = !canAllocateLineCache;
  2765. if (canAllocateLineCache)
  2766. {
  2767. HRESULT hr = this->GetUtf8SourceInfo()->EnsureLineOffsetCacheNoThrow();
  2768. if (FAILED(hr))
  2769. {
  2770. if (hr != E_OUTOFMEMORY)
  2771. {
  2772. Assert(hr == E_ABORT); // The only other possible error we know about is ScriptAbort from QueryContinue.
  2773. return false;
  2774. }
  2775. // Clear the cache so it is not used.
  2776. this->GetUtf8SourceInfo()->DeleteLineOffsetCache();
  2777. // We can try and do the slow lookup below
  2778. doSlowLookup = true;
  2779. }
  2780. }
  2781. charcount_t cacheLine = 0;
  2782. this->GetUtf8SourceInfo()->GetLineInfoForCharPosition(startCharOfStatement, &cacheLine, &column, &lineByteOffset, doSlowLookup);
  2783. // Update the tracking variables to jump to the line position (only need to jump if not on the first line).
  2784. if (cacheLine > 0)
  2785. {
  2786. line += cacheLine;
  2787. lineCharOffset = startCharOfStatement - column;
  2788. }
  2789. }
  2790. if (this->GetSourceContextInfo()->IsDynamic() && this->m_isDynamicFunction)
  2791. {
  2792. line -= JavascriptFunction::numberLinesPrependedToAnonymousFunction;
  2793. }
  2794. if(_line)
  2795. {
  2796. *_line = line;
  2797. }
  2798. if(_charOffset)
  2799. {
  2800. *_charOffset = column;
  2801. // If we are at the beginning of the host code, adjust the offset based on the host provided offset
  2802. if (this->GetHostSrcInfo()->dlnHost == line)
  2803. {
  2804. *_charOffset += (LONG)this->GetHostStartColumn();
  2805. }
  2806. }
  2807. return true;
  2808. }
  2809. bool FunctionBody::GetStatementIndexAndLengthAt(int byteCodeOffset, UINT32* statementIndex, UINT32* statementLength)
  2810. {
  2811. Assert(statementIndex != nullptr);
  2812. Assert(statementLength != nullptr);
  2813. Assert(this->IsInDebugMode());
  2814. StatementMap * statement = GetEnclosingStatementMapFromByteCode(byteCodeOffset, false);
  2815. Assert(statement != nullptr);
  2816. // Bailout if we are unable to find a statement.
  2817. // We shouldn't be missing these when a debugger is attached but we don't want to AV on retail builds.
  2818. if (statement == nullptr)
  2819. {
  2820. return false;
  2821. }
  2822. Assert(m_utf8SourceInfo);
  2823. const SRCINFO * srcInfo = GetUtf8SourceInfo()->GetSrcInfo();
  2824. // Offset from the beginning of the document minus any host-supplied source characters.
  2825. // Host supplied characters are inserted (for example) around onload:
  2826. // onload="foo('somestring', 0)" -> function onload(event).{.foo('somestring', 0).}
  2827. ULONG offsetFromDocumentBegin = srcInfo ? srcInfo->ulCharOffset - srcInfo->ichMinHost : 0;
  2828. *statementIndex = statement->sourceSpan.Begin() + offsetFromDocumentBegin;
  2829. *statementLength = statement->sourceSpan.End() - statement->sourceSpan.Begin();
  2830. return true;
  2831. }
  2832. void FunctionBody::RecordFrameDisplayRegister(RegSlot slot)
  2833. {
  2834. AssertMsg(slot != 0, "The assumption that the Frame Display Register cannot be at the 0 slot is wrong.");
  2835. SetFrameDisplayRegister(slot);
  2836. }
  2837. void FunctionBody::RecordObjectRegister(RegSlot slot)
  2838. {
  2839. AssertMsg(slot != 0, "The assumption that the Object Register cannot be at the 0 slot is wrong.");
  2840. SetObjectRegister(slot);
  2841. }
  2842. Js::RootObjectBase * FunctionBody::GetRootObject() const
  2843. {
  2844. // Safe to be used by the JIT thread
  2845. Assert(this->GetConstTable() != nullptr);
  2846. return (Js::RootObjectBase *)PointerValue(this->GetConstTable()[Js::FunctionBody::RootObjectRegSlot - FunctionBody::FirstRegSlot]);
  2847. }
  2848. Js::RootObjectBase * FunctionBody::LoadRootObject() const
  2849. {
  2850. if (this->IsES6ModuleCode() || this->GetModuleID() == kmodGlobal)
  2851. {
  2852. return JavascriptOperators::OP_LdRoot(this->GetScriptContext());
  2853. }
  2854. return JavascriptOperators::GetModuleRoot(this->GetModuleID(), this->GetScriptContext());
  2855. }
  2856. #if ENABLE_NATIVE_CODEGEN
  2857. FunctionEntryPointInfo * FunctionBody::GetEntryPointFromNativeAddress(DWORD_PTR codeAddress)
  2858. {
  2859. FunctionEntryPointInfo * entryPoint = nullptr;
  2860. this->MapEntryPoints([&entryPoint, &codeAddress](int index, FunctionEntryPointInfo * currentEntryPoint)
  2861. {
  2862. // We need to do a second check for IsNativeCode because the entry point could be in the process of
  2863. // being recorded on the background thread
  2864. if (currentEntryPoint->IsInNativeAddressRange(codeAddress))
  2865. {
  2866. entryPoint = currentEntryPoint;
  2867. }
  2868. });
  2869. return entryPoint;
  2870. }
  2871. LoopEntryPointInfo * FunctionBody::GetLoopEntryPointInfoFromNativeAddress(DWORD_PTR codeAddress, uint loopNum) const
  2872. {
  2873. LoopEntryPointInfo * entryPoint = nullptr;
  2874. LoopHeader * loopHeader = this->GetLoopHeader(loopNum);
  2875. Assert(loopHeader);
  2876. loopHeader->MapEntryPoints([&](int index, LoopEntryPointInfo * currentEntryPoint)
  2877. {
  2878. if (currentEntryPoint->IsCodeGenDone() &&
  2879. codeAddress >= currentEntryPoint->GetNativeAddress() &&
  2880. codeAddress < currentEntryPoint->GetNativeAddress() + currentEntryPoint->GetCodeSize())
  2881. {
  2882. entryPoint = currentEntryPoint;
  2883. }
  2884. });
  2885. return entryPoint;
  2886. }
  2887. int FunctionBody::GetStatementIndexFromNativeOffset(SmallSpanSequence *pThrowSpanSequence, uint32 nativeOffset)
  2888. {
  2889. int statementIndex = -1;
  2890. if (pThrowSpanSequence)
  2891. {
  2892. SmallSpanSequenceIter iter;
  2893. StatementData tmpData;
  2894. if (pThrowSpanSequence->GetMatchingStatementFromBytecode(nativeOffset, iter, tmpData))
  2895. {
  2896. statementIndex = tmpData.sourceBegin; // sourceBegin represents statementIndex here
  2897. }
  2898. else
  2899. {
  2900. // If nativeOffset falls on the last span, GetMatchingStatement would miss it because SmallSpanSequence
  2901. // does not know about the last span end. Since we checked that codeAddress is within our range,
  2902. // we can safely consider it matches the last span.
  2903. statementIndex = iter.accumulatedSourceBegin;
  2904. }
  2905. }
  2906. return statementIndex;
  2907. }
  2908. int FunctionBody::GetStatementIndexFromNativeAddress(SmallSpanSequence *pThrowSpanSequence, DWORD_PTR codeAddress, DWORD_PTR nativeBaseAddress)
  2909. {
  2910. uint32 nativeOffset = (uint32)(codeAddress - nativeBaseAddress);
  2911. return GetStatementIndexFromNativeOffset(pThrowSpanSequence, nativeOffset);
  2912. }
  2913. #endif
  2914. BOOL FunctionBody::GetMatchingStatementMap(StatementData &data, int statementIndex, FunctionBody *inlinee)
  2915. {
  2916. SourceInfo *si = &this->m_sourceInfo;
  2917. if (inlinee)
  2918. {
  2919. si = &inlinee->m_sourceInfo;
  2920. Assert(si);
  2921. }
  2922. if (statementIndex >= 0)
  2923. {
  2924. SmallSpanSequence *pSpanSequence = si->pSpanSequence;
  2925. if (pSpanSequence)
  2926. {
  2927. SmallSpanSequenceIter iter;
  2928. pSpanSequence->Reset(iter);
  2929. if (pSpanSequence->Item(statementIndex, iter, data))
  2930. {
  2931. return TRUE;
  2932. }
  2933. }
  2934. else
  2935. {
  2936. StatementMapList* pStatementMaps = GetStatementMaps();
  2937. Assert(pStatementMaps);
  2938. if (statementIndex >= pStatementMaps->Count())
  2939. {
  2940. return FALSE;
  2941. }
  2942. data.sourceBegin = pStatementMaps->Item(statementIndex)->sourceSpan.begin;
  2943. data.bytecodeBegin = pStatementMaps->Item(statementIndex)->byteCodeSpan.begin;
  2944. return TRUE;
  2945. }
  2946. }
  2947. return FALSE;
  2948. }
  2949. void FunctionBody::FindClosestStatements(int32 characterOffset, StatementLocation *firstStatementLocation, StatementLocation *secondStatementLocation)
  2950. {
  2951. auto statementMaps = this->GetStatementMaps();
  2952. if (statementMaps)
  2953. {
  2954. for(int i = 0; i < statementMaps->Count(); i++)
  2955. {
  2956. regex::Interval* pSourceSpan = &(statementMaps->Item(i)->sourceSpan);
  2957. if (FunctionBody::IsDummyGlobalRetStatement(pSourceSpan))
  2958. {
  2959. // Workaround for handling global return, which is an empty range.
  2960. continue;
  2961. }
  2962. if (pSourceSpan->begin < characterOffset
  2963. && (firstStatementLocation->function == nullptr || firstStatementLocation->statement.begin < pSourceSpan->begin))
  2964. {
  2965. firstStatementLocation->function = this;
  2966. firstStatementLocation->statement = *pSourceSpan;
  2967. firstStatementLocation->bytecodeSpan = statementMaps->Item(i)->byteCodeSpan;
  2968. }
  2969. else if (pSourceSpan->begin >= characterOffset
  2970. && (secondStatementLocation->function == nullptr || secondStatementLocation->statement.begin > pSourceSpan->begin))
  2971. {
  2972. secondStatementLocation->function = this;
  2973. secondStatementLocation->statement = *pSourceSpan;
  2974. secondStatementLocation->bytecodeSpan = statementMaps->Item(i)->byteCodeSpan;
  2975. }
  2976. }
  2977. }
  2978. }
  2979. #if ENABLE_NATIVE_CODEGEN
  2980. BOOL FunctionBody::GetMatchingStatementMapFromNativeAddress(DWORD_PTR codeAddress, StatementData &data, uint loopNum, FunctionBody *inlinee /* = nullptr */)
  2981. {
  2982. SmallSpanSequence * spanSequence = nullptr;
  2983. DWORD_PTR nativeBaseAddress = NULL;
  2984. EntryPointInfo * entryPoint;
  2985. if (loopNum == -1)
  2986. {
  2987. entryPoint = GetEntryPointFromNativeAddress(codeAddress);
  2988. }
  2989. else
  2990. {
  2991. entryPoint = GetLoopEntryPointInfoFromNativeAddress(codeAddress, loopNum);
  2992. }
  2993. if (entryPoint != nullptr)
  2994. {
  2995. spanSequence = entryPoint->GetNativeThrowSpanSequence();
  2996. nativeBaseAddress = entryPoint->GetNativeAddress();
  2997. }
  2998. int statementIndex = GetStatementIndexFromNativeAddress(spanSequence, codeAddress, nativeBaseAddress);
  2999. return GetMatchingStatementMap(data, statementIndex, inlinee);
  3000. }
  3001. BOOL FunctionBody::GetMatchingStatementMapFromNativeOffset(DWORD_PTR codeAddress, uint32 offset, StatementData &data, uint loopNum, FunctionBody *inlinee /* = nullptr */)
  3002. {
  3003. EntryPointInfo * entryPoint;
  3004. if (loopNum == -1)
  3005. {
  3006. entryPoint = GetEntryPointFromNativeAddress(codeAddress);
  3007. }
  3008. else
  3009. {
  3010. entryPoint = GetLoopEntryPointInfoFromNativeAddress(codeAddress, loopNum);
  3011. }
  3012. SmallSpanSequence *spanSequence = entryPoint ? entryPoint->GetNativeThrowSpanSequence() : nullptr;
  3013. int statementIndex = GetStatementIndexFromNativeOffset(spanSequence, offset);
  3014. return GetMatchingStatementMap(data, statementIndex, inlinee);
  3015. }
  3016. #endif
  3017. #if ENABLE_PROFILE_INFO
  3018. void FunctionBody::LoadDynamicProfileInfo()
  3019. {
  3020. SourceDynamicProfileManager * sourceDynamicProfileManager = GetSourceContextInfo()->sourceDynamicProfileManager;
  3021. if (sourceDynamicProfileManager != nullptr)
  3022. {
  3023. this->dynamicProfileInfo = sourceDynamicProfileManager->GetDynamicProfileInfo(this);
  3024. #if DBG_DUMP
  3025. if(this->dynamicProfileInfo)
  3026. {
  3027. if (Configuration::Global.flags.Dump.IsEnabled(DynamicProfilePhase, this->GetSourceContextId(), this->GetLocalFunctionId()))
  3028. {
  3029. Output::Print(_u("Loaded:"));
  3030. this->dynamicProfileInfo->Dump(this);
  3031. }
  3032. }
  3033. #endif
  3034. }
  3035. #ifdef DYNAMIC_PROFILE_MUTATOR
  3036. DynamicProfileMutator::Mutate(this);
  3037. #endif
  3038. }
  3039. bool FunctionBody::NeedEnsureDynamicProfileInfo() const
  3040. {
  3041. // Only need to ensure dynamic profile if we don't already have link up the dynamic profile info
  3042. // and dynamic profile collection is enabled
  3043. return
  3044. !this->m_isFromNativeCodeModule &&
  3045. !this->HasExecutionDynamicProfileInfo() &&
  3046. DynamicProfileInfo::IsEnabled(this);
  3047. }
  3048. DynamicProfileInfo * FunctionBody::EnsureDynamicProfileInfo()
  3049. {
  3050. if (this->NeedEnsureDynamicProfileInfo())
  3051. {
  3052. m_scriptContext->AddDynamicProfileInfo(this, this->dynamicProfileInfo);
  3053. Assert(!this->HasExecutionDynamicProfileInfo());
  3054. this->hasExecutionDynamicProfileInfo = true;
  3055. }
  3056. return this->dynamicProfileInfo;
  3057. }
  3058. DynamicProfileInfo* FunctionBody::AllocateDynamicProfile()
  3059. {
  3060. return DynamicProfileInfo::New(m_scriptContext->GetRecycler(), this);
  3061. }
  3062. #endif
  3063. BOOL FunctionBody::IsNativeOriginalEntryPoint() const
  3064. {
  3065. #if ENABLE_NATIVE_CODEGEN
  3066. JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked();
  3067. return
  3068. #if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM)
  3069. (
  3070. #if ENABLE_OOP_NATIVE_CODEGEN
  3071. JITManager::GetJITManager()->IsOOPJITEnabled()
  3072. ? JITThunkEmitter<SectionAllocWrapper>::IsInThunk(this->GetScriptContext()->GetThreadContext()->GetJITThunkStartAddr(), (uintptr_t)originalEntryPoint)
  3073. :
  3074. #endif
  3075. this->GetScriptContext()->GetThreadContext()->GetJITThunkEmitter()->IsInThunk((uintptr_t)originalEntryPoint)
  3076. ) ||
  3077. #endif
  3078. this->GetScriptContext()->IsNativeAddress((void*)originalEntryPoint);
  3079. #else
  3080. return false;
  3081. #endif
  3082. }
  3083. bool FunctionBody::IsSimpleJitOriginalEntryPoint() const
  3084. {
  3085. #if ENABLE_NATIVE_CODEGEN
  3086. const FunctionEntryPointInfo *const simpleJitEntryPointInfo = GetSimpleJitEntryPointInfo();
  3087. return simpleJitEntryPointInfo && simpleJitEntryPointInfo->GetNativeEntrypoint() == GetOriginalEntryPoint_Unchecked();
  3088. #else
  3089. return false;
  3090. #endif
  3091. }
  3092. void FunctionBody::UpdateEntryPointsOnDebugReparse()
  3093. {
  3094. // Update all function types associated with this function body. Note that we can't rely on updating
  3095. // types pointed to by function objects, because the type may evolve to one that is not currently referenced.
  3096. ProxyEntryPointInfo * entryPointInfo = this->GetDefaultFunctionEntryPointInfo();
  3097. JavascriptMethod newEntryPoint = this->GetDirectEntryPoint(entryPointInfo);
  3098. bool isAsmJS = this->GetIsAsmjsMode();
  3099. auto updateOneType = [&](ScriptFunctionType* functionType) {
  3100. // Note that the ScriptFunctionType method will handle cross-site thunks correctly.
  3101. functionType->ChangeEntryPoint(entryPointInfo, newEntryPoint, isAsmJS);
  3102. };
  3103. this->MapFunctionObjectTypes(updateOneType);
  3104. }
  3105. void FunctionProxy::Finalize(bool isShutdown)
  3106. {
  3107. this->CleanupFunctionProxyCounters();
  3108. }
  3109. #if DBG
  3110. bool FunctionBody::HasValidSourceInfo()
  3111. {
  3112. SourceContextInfo* sourceContextInfo;
  3113. if (m_scriptContext->GetSourceContextInfoMap())
  3114. {
  3115. if(m_scriptContext->GetSourceContextInfoMap()->TryGetValue(this->GetHostSourceContext(), &sourceContextInfo) &&
  3116. sourceContextInfo == this->GetSourceContextInfo())
  3117. {
  3118. return true;
  3119. }
  3120. }
  3121. Assert(this->IsDynamicScript());
  3122. if(m_scriptContext->GetDynamicSourceContextInfoMap())
  3123. {
  3124. if(m_scriptContext->GetDynamicSourceContextInfoMap()->TryGetValue(this->GetSourceContextInfo()->hash, &sourceContextInfo) &&
  3125. sourceContextInfo == this->GetSourceContextInfo())
  3126. {
  3127. return true;
  3128. }
  3129. }
  3130. // The SourceContextInfo will not be added to the dynamicSourceContextInfoMap, if they are host provided dynamic code. But they are valid source context info
  3131. if (this->GetSourceContextInfo()->isHostDynamicDocument)
  3132. {
  3133. return true;
  3134. }
  3135. return m_scriptContext->IsNoContextSourceContextInfo(this->GetSourceContextInfo());
  3136. }
  3137. // originalEntryPoint: DefaultDeferredParsingThunk, DefaultDeferredDeserializeThunk, DefaultEntryThunk, dynamic interpreter thunk or native entry point
  3138. // directEntryPoint:
  3139. // if (!profiled) - DefaultDeferredParsingThunk, DefaultDeferredDeserializeThunk, DefaultEntryThunk, CheckCodeGenThunk,
  3140. // dynamic interpreter thunk, native entry point
  3141. // if (profiling) - ProfileDeferredParsingThunk, ProfileDeferredDeserializeThunk, ProfileEntryThunk, CheckCodeGenThunk
  3142. bool FunctionProxy::HasValidNonProfileEntryPoint() const
  3143. {
  3144. JavascriptMethod directEntryPoint = this->GetDefaultEntryPointInfo()->jsMethod;
  3145. JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked();
  3146. FunctionBody* body = this->GetFunctionBody();
  3147. Unused(body); // in some configuration
  3148. #ifdef ASMJS_PLAT
  3149. if (body->GetIsAsmJsFunction())
  3150. {
  3151. #ifdef ENABLE_WASM
  3152. if (body->IsWasmFunction() && body->GetByteCodeCount() == 0)
  3153. {
  3154. // The only valid 2 entrypoints if the function hasn't been parsed
  3155. return directEntryPoint == AsmJsDefaultEntryThunk || directEntryPoint == WasmLibrary::WasmLazyTrapCallback;
  3156. }
  3157. #endif
  3158. // Entrypoints valid only for asm.js/wasm
  3159. if (directEntryPoint == AsmJsDefaultEntryThunk || IsAsmJsCodeGenThunk(directEntryPoint))
  3160. {
  3161. return true;
  3162. }
  3163. }
  3164. #endif
  3165. // Check the direct entry point to see if it is codegen thunk
  3166. // if it is not, the background codegen thread has updated both original entry point and direct entry point
  3167. // and they should still match, same as cases other then code gen
  3168. return IsIntermediateCodeGenThunk(directEntryPoint) || originalEntryPoint == directEntryPoint
  3169. #if ENABLE_PROFILE_INFO
  3170. || (directEntryPoint == DynamicProfileInfo::EnsureDynamicProfileInfoThunk && body->IsNativeOriginalEntryPoint())
  3171. #endif
  3172. ;
  3173. }
  3174. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  3175. bool FunctionProxy::HasValidProfileEntryPoint() const
  3176. {
  3177. JavascriptMethod directEntryPoint = this->GetDefaultEntryPointInfo()->jsMethod;
  3178. JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked();
  3179. if (originalEntryPoint == DefaultDeferredParsingThunk)
  3180. {
  3181. return directEntryPoint == ProfileDeferredParsingThunk;
  3182. }
  3183. if (originalEntryPoint == DefaultDeferredDeserializeThunk)
  3184. {
  3185. return directEntryPoint == ProfileDeferredDeserializeThunk;
  3186. }
  3187. if (!this->IsFunctionBody())
  3188. {
  3189. return false;
  3190. }
  3191. #if ENABLE_PROFILE_INFO
  3192. FunctionBody * functionBody = this->GetFunctionBody();
  3193. if (functionBody->IsInterpreterThunk() || functionBody->IsSimpleJitOriginalEntryPoint())
  3194. {
  3195. return directEntryPoint == ProfileEntryThunk || IsIntermediateCodeGenThunk(directEntryPoint);
  3196. }
  3197. #if ENABLE_NATIVE_CODEGEN
  3198. // In the profiler mode, the EnsureDynamicProfileInfoThunk is valid as we would be assigning to appropriate thunk when that thunk called.
  3199. return functionBody->IsNativeOriginalEntryPoint() &&
  3200. (directEntryPoint == DynamicProfileInfo::EnsureDynamicProfileInfoThunk || directEntryPoint == ProfileEntryThunk);
  3201. #endif
  3202. #else
  3203. return true;
  3204. #endif
  3205. }
  3206. #endif
  3207. bool FunctionProxy::HasValidEntryPoint() const
  3208. {
  3209. if (this->IsWasmFunction() ||
  3210. (!m_scriptContext->HadProfiled() &&
  3211. !(this->m_scriptContext->IsScriptContextInDebugMode() && m_scriptContext->IsExceptionWrapperForBuiltInsEnabled())))
  3212. {
  3213. return this->HasValidNonProfileEntryPoint();
  3214. }
  3215. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  3216. if (m_scriptContext->IsProfiling())
  3217. {
  3218. return this->HasValidProfileEntryPoint();
  3219. }
  3220. return this->HasValidNonProfileEntryPoint() || this->HasValidProfileEntryPoint();
  3221. #else
  3222. return this->HasValidNonProfileEntryPoint();
  3223. #endif
  3224. }
  3225. #endif
  3226. void ParseableFunctionInfo::SetDeferredParsingEntryPoint()
  3227. {
  3228. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  3229. Assert(m_scriptContext->DeferredParsingThunk == ProfileDeferredParsingThunk
  3230. || m_scriptContext->DeferredParsingThunk == DefaultDeferredParsingThunk);
  3231. #else
  3232. Assert(m_scriptContext->DeferredParsingThunk == DefaultDeferredParsingThunk);
  3233. #endif
  3234. this->SetEntryPoint(this->GetDefaultEntryPointInfo(), m_scriptContext->DeferredParsingThunk);
  3235. this->SetOriginalEntryPoint(DefaultDeferredParsingThunk);
  3236. }
  3237. void ParseableFunctionInfo::SetInitialDefaultEntryPoint()
  3238. {
  3239. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  3240. Assert(m_scriptContext->CurrentThunk == ProfileEntryThunk || m_scriptContext->CurrentThunk == DefaultEntryThunk);
  3241. Assert(this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredParsingThunk ||
  3242. this->GetOriginalEntryPoint_Unchecked() == ProfileDeferredParsingThunk ||
  3243. this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredDeserializeThunk ||
  3244. this->GetOriginalEntryPoint_Unchecked() == ProfileDeferredDeserializeThunk ||
  3245. this->GetOriginalEntryPoint_Unchecked() == DefaultEntryThunk ||
  3246. this->GetOriginalEntryPoint_Unchecked() == ProfileEntryThunk);
  3247. #else
  3248. Assert(m_scriptContext->CurrentThunk == DefaultEntryThunk);
  3249. Assert(this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredParsingThunk ||
  3250. this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredDeserializeThunk ||
  3251. this->GetOriginalEntryPoint_Unchecked() == DefaultEntryThunk);
  3252. #endif
  3253. Assert(this->m_defaultEntryPointInfo != nullptr);
  3254. // CONSIDER: we can optimize this to generate the dynamic interpreter thunk up front
  3255. // If we know that we are in the defer parsing thunk already
  3256. this->SetEntryPoint(this->GetDefaultEntryPointInfo(), m_scriptContext->CurrentThunk);
  3257. this->SetOriginalEntryPoint(DefaultEntryThunk);
  3258. }
  3259. #if ENABLE_NATIVE_CODEGEN
  3260. void FunctionBody::SetCheckCodeGenEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint)
  3261. {
  3262. Assert(IsIntermediateCodeGenThunk(entryPoint));
  3263. Assert(
  3264. this->GetEntryPoint(entryPointInfo) == m_scriptContext->CurrentThunk ||
  3265. (entryPointInfo == this->m_defaultEntryPointInfo && this->IsInterpreterThunk()) ||
  3266. (
  3267. GetSimpleJitEntryPointInfo() &&
  3268. GetEntryPoint(entryPointInfo) == GetSimpleJitEntryPointInfo()->GetNativeEntrypoint()
  3269. ));
  3270. this->SetEntryPoint(entryPointInfo, entryPoint);
  3271. }
  3272. #endif
  3273. #if DYNAMIC_INTERPRETER_THUNK
  3274. void FunctionBody::GenerateDynamicInterpreterThunk()
  3275. {
  3276. AssertOrFailFastMsg(!m_isWasmFunction || GetByteCodeCount() > 0, "The wasm function should have been parsed before generating the dynamic interpreter thunk");
  3277. if (this->m_dynamicInterpreterThunk == nullptr)
  3278. {
  3279. // NOTE: Etw rundown thread may be reading this->dynamicInterpreterThunk concurrently. We don't need to synchronize
  3280. // access as it is ok for etw rundown to get either null or updated new value.
  3281. if (m_isAsmJsFunction)
  3282. {
  3283. this->SetOriginalEntryPoint(this->m_scriptContext->GetNextDynamicAsmJsInterpreterThunk(&this->m_dynamicInterpreterThunk));
  3284. }
  3285. else
  3286. {
  3287. this->SetOriginalEntryPoint(this->m_scriptContext->GetNextDynamicInterpreterThunk(&this->m_dynamicInterpreterThunk));
  3288. }
  3289. if (this->m_dynamicInterpreterThunk != nullptr)
  3290. {
  3291. JS_ETW(EtwTrace::LogMethodInterpreterThunkLoadEvent(this));
  3292. }
  3293. }
  3294. else
  3295. {
  3296. this->SetOriginalEntryPoint((JavascriptMethod)InterpreterThunkEmitter::ConvertToEntryPoint(this->m_dynamicInterpreterThunk));
  3297. }
  3298. #if DBG
  3299. if (GetScriptContext()->GetThreadContext()->NoDynamicThunks())
  3300. {
  3301. Assert(this->m_dynamicInterpreterThunk == nullptr);
  3302. #ifdef ASMJS_PLAT
  3303. if (m_isAsmJsFunction)
  3304. {
  3305. Assert(this->GetOriginalEntryPoint_Unchecked() == (JavascriptMethod)&Js::InterpreterStackFrame::StaticInterpreterAsmThunk);
  3306. }
  3307. else
  3308. {
  3309. Assert(this->GetOriginalEntryPoint_Unchecked() == (JavascriptMethod)&Js::InterpreterStackFrame::StaticInterpreterThunk);
  3310. }
  3311. #else
  3312. Assert(this->GetOriginalEntryPoint_Unchecked() == (JavascriptMethod)&Js::InterpreterStackFrame::StaticInterpreterThunk);
  3313. #endif
  3314. }
  3315. #endif
  3316. }
  3317. JavascriptMethod FunctionBody::EnsureDynamicInterpreterThunk(FunctionEntryPointInfo* entryPointInfo)
  3318. {
  3319. // This may be first call to the function, make sure we have dynamic profile info
  3320. //
  3321. // We need to ensure dynamic profile info even if we didn't generate a dynamic interpreter thunk
  3322. // This happens when we go through CheckCodeGen thunk, to DelayDynamicInterpreterThunk, to here
  3323. // but the background codegen thread updated the entry point with the native entry point.
  3324. this->EnsureDynamicProfileInfo();
  3325. Assert(HasValidEntryPoint());
  3326. AssertMsg(!m_isWasmFunction || GetByteCodeCount() > 0, "Wasm function should be parsed by this point");
  3327. if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetEntryPoint(entryPointInfo)))
  3328. {
  3329. // We are not doing code gen on this function, just change the entry point directly
  3330. Assert(InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked()));
  3331. GenerateDynamicInterpreterThunk();
  3332. this->SetEntryPoint(entryPointInfo, this->GetOriginalEntryPoint_Unchecked());
  3333. }
  3334. else if (this->GetEntryPoint(entryPointInfo) == ProfileEntryThunk)
  3335. {
  3336. // We are not doing codegen on this function, just change the entry point directly
  3337. // Don't replace the profile entry thunk
  3338. Assert(InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked()));
  3339. GenerateDynamicInterpreterThunk();
  3340. }
  3341. else if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked()))
  3342. {
  3343. JsUtil::JobProcessor * jobProcessor = this->GetScriptContext()->GetThreadContext()->GetJobProcessor();
  3344. if (jobProcessor->ProcessesInBackground())
  3345. {
  3346. JsUtil::BackgroundJobProcessor * backgroundJobProcessor = static_cast<JsUtil::BackgroundJobProcessor *>(jobProcessor);
  3347. AutoCriticalSection autocs(backgroundJobProcessor->GetCriticalSection());
  3348. // Check again under lock
  3349. if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked()))
  3350. {
  3351. // If the original entry point is DelayDynamicInterpreterThunk then there must be a version of this
  3352. // function being codegen'd.
  3353. Assert(IsIntermediateCodeGenThunk((JavascriptMethod)this->GetEntryPoint(this->GetDefaultEntryPointInfo())) || IsAsmJsCodeGenThunk((JavascriptMethod)this->GetEntryPoint(this->GetDefaultEntryPointInfo())));
  3354. GenerateDynamicInterpreterThunk();
  3355. }
  3356. }
  3357. else
  3358. {
  3359. // If the original entry point is DelayDynamicInterpreterThunk then there must be a version of this
  3360. // function being codegen'd.
  3361. Assert(IsIntermediateCodeGenThunk((JavascriptMethod)this->GetEntryPoint(this->GetDefaultEntryPointInfo())) || IsAsmJsCodeGenThunk((JavascriptMethod)this->GetEntryPoint(this->GetDefaultEntryPointInfo())));
  3362. GenerateDynamicInterpreterThunk();
  3363. }
  3364. }
  3365. return this->GetOriginalEntryPoint_Unchecked();
  3366. }
  3367. #endif
  3368. #if ENABLE_NATIVE_CODEGEN
  3369. void FunctionBody::SetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod originalEntryPoint, JavascriptMethod directEntryPoint)
  3370. {
  3371. if (entryPointInfo->IsNativeEntryPointProcessed())
  3372. {
  3373. return;
  3374. }
  3375. bool isAsmJs = this->GetIsAsmjsMode();
  3376. Assert(IsIntermediateCodeGenThunk(entryPointInfo->jsMethod) || CONFIG_FLAG(Prejit) || this->m_isFromNativeCodeModule || isAsmJs);
  3377. entryPointInfo->EnsureIsReadyToCall();
  3378. // keep originalEntryPoint updated with the latest known good native entry point
  3379. if (entryPointInfo == this->GetDefaultEntryPointInfo())
  3380. {
  3381. this->SetOriginalEntryPoint(originalEntryPoint);
  3382. }
  3383. if (entryPointInfo->entryPointIndex == 0 && this->NeedEnsureDynamicProfileInfo())
  3384. {
  3385. entryPointInfo->jsMethod = DynamicProfileInfo::EnsureDynamicProfileInfoThunk;
  3386. }
  3387. else
  3388. {
  3389. entryPointInfo->jsMethod = directEntryPoint;
  3390. }
  3391. this->CaptureDynamicProfileState(entryPointInfo);
  3392. if(entryPointInfo->GetJitMode() == ExecutionMode::SimpleJit)
  3393. {
  3394. Assert(GetExecutionMode() == ExecutionMode::SimpleJit);
  3395. SetSimpleJitEntryPointInfo(entryPointInfo);
  3396. ResetSimpleJitCallCount();
  3397. }
  3398. else
  3399. {
  3400. Assert(entryPointInfo->GetJitMode() == ExecutionMode::FullJit);
  3401. Assert(isAsmJs || GetExecutionMode() == ExecutionMode::FullJit);
  3402. entryPointInfo->callsCount =
  3403. static_cast<uint8>(
  3404. min(
  3405. static_cast<uint>(static_cast<uint8>(CONFIG_FLAG(MinBailOutsBeforeRejit))) *
  3406. (Js::FunctionEntryPointInfo::GetDecrCallCountPerBailout() - 1),
  3407. 0xffu));
  3408. }
  3409. TraceExecutionMode();
  3410. JS_ETW(EtwTrace::LogMethodNativeLoadEvent(this, entryPointInfo));
  3411. #ifdef VTUNE_PROFILING
  3412. VTuneChakraProfile::LogMethodNativeLoadEvent(this, entryPointInfo);
  3413. #endif
  3414. #ifdef _M_ARM
  3415. // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
  3416. _InstructionSynchronizationBarrier();
  3417. #endif
  3418. entryPointInfo->SetNativeEntryPointProcessed();
  3419. }
  3420. void FunctionBody::DefaultSetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, FunctionBody * functionBody, JavascriptMethod entryPoint)
  3421. {
  3422. Assert(functionBody->m_scriptContext->CurrentThunk == DefaultEntryThunk);
  3423. functionBody->SetNativeEntryPoint(entryPointInfo, entryPoint, entryPoint);
  3424. }
  3425. void FunctionBody::ProfileSetNativeEntryPoint(FunctionEntryPointInfo* entryPointInfo, FunctionBody * functionBody, JavascriptMethod entryPoint)
  3426. {
  3427. #ifdef ENABLE_WASM
  3428. // Do not profile WebAssembly functions
  3429. if (functionBody->IsWasmFunction())
  3430. {
  3431. functionBody->SetNativeEntryPoint(entryPointInfo, entryPoint, entryPoint);
  3432. return;
  3433. }
  3434. #endif
  3435. Assert(functionBody->m_scriptContext->CurrentThunk == ProfileEntryThunk);
  3436. functionBody->SetNativeEntryPoint(entryPointInfo, entryPoint, ProfileEntryThunk);
  3437. }
  3438. Js::JavascriptMethod FunctionBody::GetLoopBodyEntryPoint(Js::LoopHeader * loopHeader, int entryPointIndex)
  3439. {
  3440. #if DBG
  3441. this->GetLoopNumber(loopHeader);
  3442. #endif
  3443. return loopHeader->GetEntryPointInfo(entryPointIndex)->jsMethod;
  3444. }
  3445. void FunctionBody::SetLoopBodyEntryPoint(Js::LoopHeader * loopHeader, EntryPointInfo* entryPointInfo, Js::JavascriptMethod entryPoint, uint loopNum)
  3446. {
  3447. #if DBG_DUMP
  3448. if (PHASE_TRACE1(Js::JITLoopBodyPhase))
  3449. {
  3450. DumpFunctionId(true);
  3451. Output::Print(_u(": %-20s LoopBody EntryPt Loop: %2d Address : %x\n"), GetDisplayName(), loopNum, entryPoint);
  3452. Output::Flush();
  3453. }
  3454. #endif
  3455. Assert(((LoopEntryPointInfo*)entryPointInfo)->loopHeader == loopHeader);
  3456. Assert(reinterpret_cast<void*>(entryPointInfo->jsMethod) == nullptr);
  3457. entryPointInfo->jsMethod = entryPoint;
  3458. ((Js::LoopEntryPointInfo*)entryPointInfo)->totalJittedLoopIterations =
  3459. static_cast<uint8>(
  3460. min(
  3461. static_cast<uint>(static_cast<uint8>(CONFIG_FLAG(MinBailOutsBeforeRejitForLoops))) *
  3462. (Js::LoopEntryPointInfo::GetDecrLoopCountPerBailout() - 1),
  3463. 0xffu));
  3464. // reset the counter to 1 less than the threshold for TJLoopBody
  3465. if (loopHeader->GetCurrentEntryPointInfo()->GetIsAsmJSFunction())
  3466. {
  3467. loopHeader->interpretCount = entryPointInfo->GetFunctionBody()->GetLoopInterpretCount(loopHeader) - 1;
  3468. }
  3469. JS_ETW(EtwTrace::LogLoopBodyLoadEvent(this, ((LoopEntryPointInfo*)entryPointInfo), ((uint16)loopNum)));
  3470. #ifdef VTUNE_PROFILING
  3471. VTuneChakraProfile::LogLoopBodyLoadEvent(this, ((LoopEntryPointInfo*)entryPointInfo), ((uint16)loopNum));
  3472. #endif
  3473. }
  3474. #endif
  3475. void FunctionBody::MarkScript(ByteBlock *byteCodeBlock, ByteBlock* auxBlock, ByteBlock* auxContextBlock,
  3476. uint byteCodeCount, uint byteCodeInLoopCount, uint byteCodeWithoutLDACount)
  3477. {
  3478. CheckNotExecuting();
  3479. CheckEmpty();
  3480. #ifdef PERF_COUNTERS
  3481. DWORD byteCodeSize = byteCodeBlock->GetLength()
  3482. + (auxBlock? auxBlock->GetLength() : 0)
  3483. + (auxContextBlock? auxContextBlock->GetLength() : 0);
  3484. PERF_COUNTER_ADD(Code, DynamicByteCodeSize, byteCodeSize);
  3485. #endif
  3486. SetByteCodeCount(byteCodeCount);
  3487. SetByteCodeInLoopCount(byteCodeInLoopCount);
  3488. SetByteCodeWithoutLDACount(byteCodeWithoutLDACount);
  3489. executionState.InitializeExecutionModeAndLimits(this);
  3490. this->SetAuxiliaryData(auxBlock);
  3491. this->SetAuxiliaryContextData(auxContextBlock);
  3492. // Memory barrier needed here to make sure the background codegen thread's inliner
  3493. // gets all the assignment before it sees that the function has been parse
  3494. MemoryBarrier();
  3495. this->byteCodeBlock = byteCodeBlock;
  3496. PERF_COUNTER_ADD(Code, TotalByteCodeSize, byteCodeSize);
  3497. // If this is a defer parse function body, we would not have registered it
  3498. // on the function bodies list so we should register it now
  3499. if (!this->m_isFuncRegistered)
  3500. {
  3501. this->GetUtf8SourceInfo()->SetFunctionBody(this);
  3502. }
  3503. }
  3504. uint
  3505. FunctionBody::GetLoopNumber(LoopHeader const * loopHeader) const
  3506. {
  3507. LoopHeader* loopHeaderArray = this->GetLoopHeaderArray();
  3508. Assert(loopHeader >= loopHeaderArray);
  3509. uint loopNum = (uint)(loopHeader - loopHeaderArray);
  3510. Assert(loopNum < GetLoopCount());
  3511. return loopNum;
  3512. }
  3513. uint
  3514. FunctionBody::GetLoopNumberWithLock(LoopHeader const * loopHeader) const
  3515. {
  3516. LoopHeader* loopHeaderArray = this->GetLoopHeaderArrayWithLock();
  3517. Assert(loopHeader >= loopHeaderArray);
  3518. uint loopNum = (uint)(loopHeader - loopHeaderArray);
  3519. Assert(loopNum < GetLoopCount());
  3520. return loopNum;
  3521. }
  3522. #ifdef ENABLE_SCRIPT_DEBUGGING
  3523. bool FunctionBody::InstallProbe(int offset)
  3524. {
  3525. if (offset < 0 || ((uint)offset + 1) >= byteCodeBlock->GetLength())
  3526. {
  3527. return false;
  3528. }
  3529. byte* pbyteCodeBlockBuffer = this->byteCodeBlock->GetBuffer();
  3530. if(!GetProbeBackingBlock())
  3531. {
  3532. // The probe backing block is set on a different thread than the main thread
  3533. // The recycler doesn't like allocations from a different thread, so we allocate
  3534. // the backing byte code block in the arena
  3535. ArenaAllocator *pArena = m_scriptContext->AllocatorForDiagnostics();
  3536. Assert(pArena);
  3537. ByteBlock* probeBackingBlock = ByteBlock::NewFromArena(pArena, pbyteCodeBlockBuffer, byteCodeBlock->GetLength());
  3538. SetProbeBackingBlock(probeBackingBlock);
  3539. }
  3540. // Make sure Break opcode only need one byte
  3541. Assert(OpCodeUtil::IsSmallEncodedOpcode(OpCode::Break));
  3542. #if ENABLE_NATIVE_CODEGEN
  3543. Assert(!OpCodeAttr::HasMultiSizeLayout(OpCode::Break));
  3544. #endif
  3545. *(byte *)(pbyteCodeBlockBuffer + offset) = (byte)OpCode::Break;
  3546. ++m_sourceInfo.m_probeCount;
  3547. return true;
  3548. }
  3549. bool FunctionBody::UninstallProbe(int offset)
  3550. {
  3551. if (offset < 0 || ((uint)offset + 1) >= byteCodeBlock->GetLength())
  3552. {
  3553. return false;
  3554. }
  3555. byte* pbyteCodeBlockBuffer = byteCodeBlock->GetBuffer();
  3556. Js::OpCode originalOpCode = ByteCodeReader::PeekByteOp(GetProbeBackingBlock()->GetBuffer() + offset);
  3557. *(pbyteCodeBlockBuffer + offset) = (byte)originalOpCode;
  3558. --m_sourceInfo.m_probeCount;
  3559. AssertMsg(m_sourceInfo.m_probeCount >= 0, "Probe (Break Point) count became negative!");
  3560. return true;
  3561. }
  3562. bool FunctionBody::ProbeAtOffset(int offset, OpCode* pOriginalOpcode)
  3563. {
  3564. if (!GetProbeBackingBlock())
  3565. {
  3566. return false;
  3567. }
  3568. if (offset < 0 || ((uint)offset + 1) >= this->byteCodeBlock->GetLength())
  3569. {
  3570. AssertMsg(false, "ProbeAtOffset called with out of bounds offset");
  3571. return false;
  3572. }
  3573. Js::OpCode runningOpCode = ByteCodeReader::PeekByteOp(this->byteCodeBlock->GetBuffer() + offset);
  3574. Js::OpCode originalOpcode = ByteCodeReader::PeekByteOp(GetProbeBackingBlock()->GetBuffer() + offset);
  3575. if ( runningOpCode != originalOpcode)
  3576. {
  3577. *pOriginalOpcode = originalOpcode;
  3578. return true;
  3579. }
  3580. else
  3581. {
  3582. // e.g. inline break or a step hit and is checking for a bp
  3583. return false;
  3584. }
  3585. }
  3586. #endif
  3587. void FunctionBody::SetStackNestedFuncParent(FunctionInfo * parentFunctionInfo)
  3588. {
  3589. FunctionBody * parentFunctionBody = parentFunctionInfo->GetFunctionBody();
  3590. RecyclerWeakReference<FunctionInfo>* parent = this->GetStackNestedFuncParent();
  3591. if (parent != nullptr)
  3592. {
  3593. Assert(parent->Get() == parentFunctionInfo);
  3594. return;
  3595. }
  3596. // Redeferral invalidates this assertion, as we may be recompiling with a different view of nested functions and
  3597. // thus making different stack-nested-function decisions. I'm inclined to allow this, since things that have been
  3598. // re-deferred will likely not be executed again, so it makes sense to exclude them from our analysis.
  3599. // Assert(CanDoStackNestedFunc());
  3600. Assert(parentFunctionBody->DoStackNestedFunc());
  3601. this->SetAuxPtr<AuxPointerType::StackNestedFuncParent>(this->GetScriptContext()->GetRecycler()->CreateWeakReferenceHandle(parentFunctionInfo));
  3602. }
  3603. FunctionInfo * FunctionBody::GetStackNestedFuncParentStrongRef()
  3604. {
  3605. Assert(this->GetStackNestedFuncParent() != nullptr);
  3606. return this->GetStackNestedFuncParent()->Get();
  3607. }
  3608. RecyclerWeakReference<FunctionInfo> * FunctionBody::GetStackNestedFuncParent()
  3609. {
  3610. return this->GetAuxPtr<AuxPointerType::StackNestedFuncParent>();
  3611. }
  3612. FunctionInfo * FunctionBody::GetAndClearStackNestedFuncParent()
  3613. {
  3614. if (this->GetAuxPtr<AuxPointerType::StackNestedFuncParent>())
  3615. {
  3616. FunctionInfo * parentFunctionInfo = GetStackNestedFuncParentStrongRef();
  3617. ClearStackNestedFuncParent();
  3618. return parentFunctionInfo;
  3619. }
  3620. return nullptr;
  3621. }
  3622. void FunctionBody::ClearStackNestedFuncParent()
  3623. {
  3624. this->SetAuxPtr<AuxPointerType::StackNestedFuncParent>(nullptr);
  3625. }
  3626. void FunctionBody::CreateCacheIdToPropertyIdMap(uint rootObjectLoadInlineCacheStart, uint rootObjectLoadMethodInlineCacheStart,
  3627. uint rootObjectStoreInlineCacheStart,
  3628. uint totalFieldAccessInlineCacheCount, uint isInstInlineCacheCount)
  3629. {
  3630. Assert(this->GetRootObjectLoadInlineCacheStart() == 0);
  3631. Assert(this->GetRootObjectLoadMethodInlineCacheStart() == 0);
  3632. Assert(this->GetRootObjectStoreInlineCacheStart() == 0);
  3633. Assert(this->GetInlineCacheCount() == 0);
  3634. Assert(this->GetIsInstInlineCacheCount() == 0);
  3635. this->SetRootObjectLoadInlineCacheStart(rootObjectLoadInlineCacheStart);
  3636. this->SetRootObjectLoadMethodInlineCacheStart(rootObjectLoadMethodInlineCacheStart);
  3637. this->SetRootObjectStoreInlineCacheStart(rootObjectStoreInlineCacheStart);
  3638. this->SetInlineCacheCount(totalFieldAccessInlineCacheCount);
  3639. this->SetIsInstInlineCacheCount(isInstInlineCacheCount);
  3640. this->CreateCacheIdToPropertyIdMap();
  3641. }
  3642. void FunctionBody::CreateCacheIdToPropertyIdMap()
  3643. {
  3644. Assert(this->cacheIdToPropertyIdMap == nullptr);
  3645. Assert(this->inlineCaches == nullptr);
  3646. uint count = this->GetInlineCacheCount() ;
  3647. if (count!= 0)
  3648. {
  3649. this->cacheIdToPropertyIdMap =
  3650. RecyclerNewArrayLeaf(this->m_scriptContext->GetRecycler(), PropertyId, count);
  3651. #if DBG
  3652. for (uint i = 0; i < count; i++)
  3653. {
  3654. this->cacheIdToPropertyIdMap[i] = Js::Constants::NoProperty;
  3655. }
  3656. #endif
  3657. }
  3658. }
  3659. #if DBG
  3660. void FunctionBody::VerifyCacheIdToPropertyIdMap()
  3661. {
  3662. uint count = this->GetInlineCacheCount();
  3663. for (uint i = 0; i < count; i++)
  3664. {
  3665. Assert(this->cacheIdToPropertyIdMap[i] != Js::Constants::NoProperty);
  3666. }
  3667. }
  3668. #endif
  3669. void FunctionBody::SetPropertyIdForCacheId(uint cacheId, PropertyId propertyId)
  3670. {
  3671. Assert(this->cacheIdToPropertyIdMap != nullptr);
  3672. Assert(cacheId < this->GetInlineCacheCount());
  3673. Assert(this->cacheIdToPropertyIdMap[cacheId] == Js::Constants::NoProperty);
  3674. this->cacheIdToPropertyIdMap[cacheId] = propertyId;
  3675. }
  3676. void FunctionBody::CreateReferencedPropertyIdMap(uint referencedPropertyIdCount)
  3677. {
  3678. this->SetReferencedPropertyIdCount(referencedPropertyIdCount);
  3679. this->CreateReferencedPropertyIdMap();
  3680. }
  3681. void FunctionBody::CreateReferencedPropertyIdMap()
  3682. {
  3683. Assert(this->GetReferencedPropertyIdMap() == nullptr);
  3684. uint count = this->GetReferencedPropertyIdCount();
  3685. if (count!= 0)
  3686. {
  3687. this->SetReferencedPropertyIdMap(RecyclerNewArrayLeaf(this->m_scriptContext->GetRecycler(), PropertyId, count));
  3688. #if DBG
  3689. for (uint i = 0; i < count; i++)
  3690. {
  3691. this->GetReferencedPropertyIdMap()[i] = Js::Constants::NoProperty;
  3692. }
  3693. #endif
  3694. }
  3695. }
  3696. #if DBG
  3697. void FunctionBody::VerifyReferencedPropertyIdMap()
  3698. {
  3699. uint count = this->GetReferencedPropertyIdCount();
  3700. for (uint i = 0; i < count; i++)
  3701. {
  3702. Assert(this->GetReferencedPropertyIdMap()[i] != Js::Constants::NoProperty);
  3703. }
  3704. }
  3705. #endif
  3706. PropertyId FunctionBody::GetReferencedPropertyId(uint index)
  3707. {
  3708. if (index < (uint)TotalNumberOfBuiltInProperties)
  3709. {
  3710. return index;
  3711. }
  3712. uint mapIndex = index - TotalNumberOfBuiltInProperties;
  3713. return GetReferencedPropertyIdWithMapIndex(mapIndex);
  3714. }
  3715. PropertyId FunctionBody::GetReferencedPropertyIdWithLock(uint index)
  3716. {
  3717. if (index < (uint)TotalNumberOfBuiltInProperties)
  3718. {
  3719. return index;
  3720. }
  3721. uint mapIndex = index - TotalNumberOfBuiltInProperties;
  3722. return GetReferencedPropertyIdWithMapIndexWithLock(mapIndex);
  3723. }
  3724. PropertyId FunctionBody::GetReferencedPropertyIdWithMapIndex(uint mapIndex)
  3725. {
  3726. Assert(this->GetReferencedPropertyIdMap());
  3727. Assert(mapIndex < this->GetReferencedPropertyIdCount());
  3728. return this->GetReferencedPropertyIdMap()[mapIndex];
  3729. }
  3730. PropertyId FunctionBody::GetReferencedPropertyIdWithMapIndexWithLock(uint mapIndex)
  3731. {
  3732. Assert(this->GetReferencedPropertyIdMapWithLock());
  3733. Assert(mapIndex < this->GetReferencedPropertyIdCount());
  3734. return this->GetReferencedPropertyIdMapWithLock()[mapIndex];
  3735. }
  3736. void FunctionBody::SetReferencedPropertyIdWithMapIndex(uint mapIndex, PropertyId propertyId)
  3737. {
  3738. Assert(propertyId >= TotalNumberOfBuiltInProperties);
  3739. Assert(mapIndex < this->GetReferencedPropertyIdCount());
  3740. Assert(this->GetReferencedPropertyIdMap() != nullptr);
  3741. Assert(this->GetReferencedPropertyIdMap()[mapIndex] == Js::Constants::NoProperty);
  3742. this->GetReferencedPropertyIdMap()[mapIndex] = propertyId;
  3743. }
  3744. void FunctionBody::CreateConstantTable()
  3745. {
  3746. Assert(this->GetConstTable() == nullptr);
  3747. Assert(GetConstantCount() > FirstRegSlot);
  3748. this->SetConstTable(RecyclerNewArrayZ(this->m_scriptContext->GetRecycler(), Field(Var), GetConstantCount()));
  3749. // Initialize with the root object, which will always be recorded here.
  3750. Js::RootObjectBase * rootObject = this->LoadRootObject();
  3751. if (rootObject)
  3752. {
  3753. this->RecordConstant(RootObjectRegSlot, rootObject);
  3754. }
  3755. else
  3756. {
  3757. Assert(false);
  3758. this->RecordConstant(RootObjectRegSlot, this->m_scriptContext->GetLibrary()->GetUndefined());
  3759. }
  3760. }
  3761. void FunctionBody::RecordConstant(RegSlot location, Var var)
  3762. {
  3763. Assert(location < GetConstantCount());
  3764. Assert(this->GetConstTable());
  3765. Assert(var != nullptr);
  3766. Assert(this->GetConstTable()[location - FunctionBody::FirstRegSlot] == nullptr);
  3767. this->GetConstTable()[location - FunctionBody::FirstRegSlot] = var;
  3768. }
  3769. void FunctionBody::RecordNullObject(RegSlot location)
  3770. {
  3771. ScriptContext *scriptContext = this->GetScriptContext();
  3772. Var nullObject = JavascriptOperators::OP_LdNull(scriptContext);
  3773. this->RecordConstant(location, nullObject);
  3774. }
  3775. void FunctionBody::RecordUndefinedObject(RegSlot location)
  3776. {
  3777. ScriptContext *scriptContext = this->GetScriptContext();
  3778. Var undefObject = JavascriptOperators::OP_LdUndef(scriptContext);
  3779. this->RecordConstant(location, undefObject);
  3780. }
  3781. void FunctionBody::RecordTrueObject(RegSlot location)
  3782. {
  3783. ScriptContext *scriptContext = this->GetScriptContext();
  3784. Var trueObject = JavascriptBoolean::OP_LdTrue(scriptContext);
  3785. this->RecordConstant(location, trueObject);
  3786. }
  3787. void FunctionBody::RecordFalseObject(RegSlot location)
  3788. {
  3789. ScriptContext *scriptContext = this->GetScriptContext();
  3790. Var falseObject = JavascriptBoolean::OP_LdFalse(scriptContext);
  3791. this->RecordConstant(location, falseObject);
  3792. }
  3793. void FunctionBody::RecordIntConstant(RegSlot location, unsigned int val)
  3794. {
  3795. ScriptContext *scriptContext = this->GetScriptContext();
  3796. Var intConst = JavascriptNumber::ToVar((int32)val, scriptContext);
  3797. this->RecordConstant(location, intConst);
  3798. }
  3799. void FunctionBody::RecordStrConstant(RegSlot location, LPCOLESTR psz, uint32 cch, bool forcePropertyString)
  3800. {
  3801. ScriptContext *scriptContext = this->GetScriptContext();
  3802. PropertyRecord const * propertyRecord;
  3803. if (forcePropertyString)
  3804. {
  3805. scriptContext->GetOrAddPropertyRecord(psz, cch, &propertyRecord);
  3806. }
  3807. else
  3808. {
  3809. scriptContext->FindPropertyRecord(psz, cch, &propertyRecord);
  3810. }
  3811. Var str;
  3812. if (propertyRecord == nullptr)
  3813. {
  3814. str = JavascriptString::NewCopyBuffer(psz, cch, scriptContext);
  3815. }
  3816. else
  3817. {
  3818. // If a particular string constant already has a propertyId, just create a property string for it
  3819. // as it might be likely that it is used for a property lookup
  3820. str = scriptContext->GetPropertyString(propertyRecord->GetPropertyId());
  3821. }
  3822. this->RecordConstant(location, str);
  3823. }
  3824. void FunctionBody::RecordBigIntConstant(RegSlot location, LPCOLESTR psz, uint32 cch, bool isNegative)
  3825. {
  3826. ScriptContext *scriptContext = this->GetScriptContext();
  3827. Var bigintConst = JavascriptBigInt::Create(psz, cch, isNegative, scriptContext);
  3828. this->RecordConstant(location, bigintConst);
  3829. }
  3830. void FunctionBody::RecordFloatConstant(RegSlot location, double d)
  3831. {
  3832. ScriptContext *scriptContext = this->GetScriptContext();
  3833. Var floatConst = JavascriptNumber::ToVarIntCheck(d, scriptContext);
  3834. this->RecordConstant(location, floatConst);
  3835. }
  3836. void FunctionBody::RecordNullDisplayConstant(RegSlot location)
  3837. {
  3838. this->RecordConstant(location, (Js::Var)&Js::NullFrameDisplay);
  3839. }
  3840. void FunctionBody::RecordStrictNullDisplayConstant(RegSlot location)
  3841. {
  3842. this->RecordConstant(location, (Js::Var)&Js::StrictNullFrameDisplay);
  3843. }
  3844. void FunctionBody::InitConstantSlots(Var *dstSlots)
  3845. {
  3846. // Initialize the given slots from the constant table.
  3847. uint32 constCount = GetConstantCount();
  3848. Assert(constCount > FunctionBody::FirstRegSlot);
  3849. js_memcpy_s(dstSlots, (constCount - FunctionBody::FirstRegSlot) * sizeof(Var),
  3850. this->GetConstTable(), (constCount - FunctionBody::FirstRegSlot) * sizeof(Var));
  3851. }
  3852. Var FunctionBody::GetConstantVar(RegSlot location)
  3853. {
  3854. Assert(this->GetConstTable());
  3855. Assert(location < GetConstantCount());
  3856. Assert(location != 0);
  3857. return this->GetConstTable()[location - FunctionBody::FirstRegSlot];
  3858. }
  3859. #if DBG_DUMP
  3860. void FunctionBody::Dump()
  3861. {
  3862. Js::ByteCodeDumper::Dump(this);
  3863. }
  3864. void FunctionBody::DumpScopes()
  3865. {
  3866. if(this->GetScopeObjectChain())
  3867. {
  3868. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  3869. Output::Print(_u("%s (%s) :\n"), this->GetDisplayName(), this->GetDebugNumberSet(debugStringBuffer));
  3870. this->GetScopeObjectChain()->pScopeChain->Map( [=] (uint index, DebuggerScope* scope )
  3871. {
  3872. scope->Dump();
  3873. });
  3874. }
  3875. }
  3876. #if ENABLE_NATIVE_CODEGEN
  3877. void EntryPointInfo::DumpNativeOffsetMaps()
  3878. {
  3879. // Native Offsets
  3880. if (this->HasNativeEntryPointData())
  3881. {
  3882. auto& nativeOffsetMaps = this->GetNativeEntryPointData()->GetNativeOffsetMaps();
  3883. if (nativeOffsetMaps.Count() > 0)
  3884. {
  3885. Output::Print(_u("Native Map: baseAddr: 0x%0Ix, size: 0x%0Ix\nstatementId, offset range, address range\n"),
  3886. this->GetNativeAddress(),
  3887. this->GetCodeSize());
  3888. int count = nativeOffsetMaps.Count();
  3889. for (int i = 0; i < count; i++)
  3890. {
  3891. const NativeEntryPointData::NativeOffsetMap* map = &nativeOffsetMaps.Item(i);
  3892. Output::Print(_u("S%4d, (%5d, %5d) (0x%012Ix, 0x%012Ix)\n"), map->statementIndex,
  3893. map->nativeOffsetSpan.begin,
  3894. map->nativeOffsetSpan.end,
  3895. map->nativeOffsetSpan.begin + this->GetNativeAddress(),
  3896. map->nativeOffsetSpan.end + this->GetNativeAddress());
  3897. }
  3898. }
  3899. }
  3900. }
  3901. #endif
  3902. void FunctionBody::DumpStatementMaps()
  3903. {
  3904. // Source Map to ByteCode
  3905. StatementMapList * pStatementMaps = this->GetStatementMaps();
  3906. if (pStatementMaps)
  3907. {
  3908. Output::Print(_u("Statement Map:\nstatementId, SourceSpan, ByteCodeSpan\n"));
  3909. int count = pStatementMaps->Count();
  3910. for(int i = 0; i < count; i++)
  3911. {
  3912. StatementMap* map = pStatementMaps->Item(i);
  3913. Output::Print(_u("S%4d, (C%5d, C%5d) (B%5d, B%5d) Inner=%d\n"), i,
  3914. map->sourceSpan.begin,
  3915. map->sourceSpan.end,
  3916. map->byteCodeSpan.begin,
  3917. map->byteCodeSpan.end,
  3918. map->isSubexpression);
  3919. }
  3920. }
  3921. }
  3922. #if ENABLE_NATIVE_CODEGEN
  3923. void EntryPointInfo::DumpNativeThrowSpanSequence()
  3924. {
  3925. // Native Throw Map
  3926. SmallSpanSequence * nativeThrowSpanSequence = this->GetNativeEntryPointData()->GetNativeThrowSpanSequence();
  3927. if (nativeThrowSpanSequence)
  3928. {
  3929. Output::Print(_u("Native Throw Map: baseAddr: 0x%0Ix, size: 0x%Ix\nstatementId, offset range, address range\n"),
  3930. this->GetNativeAddress(),
  3931. this->GetCodeSize());
  3932. int count = nativeThrowSpanSequence->Count();
  3933. SmallSpanSequenceIter iter;
  3934. for (int i = 0; i < count; i++)
  3935. {
  3936. StatementData data;
  3937. if (nativeThrowSpanSequence->Item(i, iter, data))
  3938. {
  3939. Output::Print(_u("S%4d, (%5d -----) (0x%012Ix --------)\n"), data.sourceBegin, // statementIndex
  3940. data.bytecodeBegin, // nativeOffset
  3941. data.bytecodeBegin + this->GetNativeAddress());
  3942. }
  3943. }
  3944. }
  3945. }
  3946. #endif
  3947. void FunctionBody::PrintStatementSourceLine(uint statementIndex)
  3948. {
  3949. if (m_isWasmFunction || this->GetUtf8SourceInfo()->GetIsLibraryCode())
  3950. {
  3951. // currently no source view support for wasm
  3952. return;
  3953. }
  3954. const uint startOffset = GetStatementStartOffset(statementIndex);
  3955. // startOffset should only be 0 if statementIndex is 0, otherwise it is EOF and we should skip printing anything
  3956. if (startOffset != 0 || statementIndex == 0)
  3957. {
  3958. PrintStatementSourceLineFromStartOffset(startOffset);
  3959. }
  3960. }
  3961. void FunctionBody::PrintStatementSourceLineFromStartOffset(uint cchStartOffset)
  3962. {
  3963. ULONG line;
  3964. LONG col;
  3965. LPCUTF8 source = GetStartOfDocument(_u("FunctionBody::PrintStatementSourceLineFromStartOffset"));
  3966. Utf8SourceInfo* sourceInfo = this->GetUtf8SourceInfo();
  3967. Assert(sourceInfo != nullptr);
  3968. LPCUTF8 sourceInfoSrc = sourceInfo->GetSource(_u("FunctionBody::PrintStatementSourceLineFromStartOffset"));
  3969. if(!sourceInfoSrc)
  3970. {
  3971. Assert(sourceInfo->GetIsLibraryCode());
  3972. return;
  3973. }
  3974. if( source != sourceInfoSrc )
  3975. {
  3976. Output::Print(_u("\nDETECTED MISMATCH:\n"));
  3977. Output::Print(_u("GetUtf8SourceInfo()->GetSource(): 0x%08X: %.*s ...\n"), sourceInfo, 16, sourceInfo);
  3978. Output::Print(_u("GetStartOfDocument(): 0x%08X: %.*s ...\n"), source, 16, source);
  3979. AssertMsg(false, "Non-matching start of document");
  3980. }
  3981. GetLineCharOffsetFromStartChar(cchStartOffset, &line, &col, false /*canAllocateLineCache*/);
  3982. if (sourceInfo->GetSourceHolder() != ISourceHolder::GetEmptySourceHolder())
  3983. {
  3984. WORD color = 0;
  3985. if (Js::Configuration::Global.flags.DumpLineNoInColor)
  3986. {
  3987. color = Output::SetConsoleForeground(12);
  3988. }
  3989. Output::Print(_u("\n\n Line %3d: "), line + 1);
  3990. // Need to match up cchStartOffset to appropriate cbStartOffset given function's cbStartOffset and cchStartOffset
  3991. size_t utf8SrcStartIdx = utf8::CharacterIndexToByteIndex(source, sourceInfo->GetCbLength(), cchStartOffset, this->m_cbStartOffset, this->m_cchStartOffset);
  3992. size_t utf8SrcEndIdx = StartOffset() + LengthInBytes();
  3993. char16* utf16Buf = HeapNewArray(char16, utf8SrcEndIdx - utf8SrcStartIdx + 2);
  3994. size_t utf16BufSz = utf8::DecodeUnitsIntoAndNullTerminateNoAdvance(utf16Buf, source + utf8SrcStartIdx, source + utf8SrcEndIdx, utf8::DecodeOptions::doDefault);
  3995. Assert(utf16BufSz <= utf8SrcEndIdx - utf8SrcStartIdx);
  3996. for (size_t i = 0; i < utf16BufSz && utf16Buf[i] != _u('\n') && utf16Buf[i] != _u('\r'); i++)
  3997. {
  3998. Output::Print(_u("%lc"), utf16Buf[i]);
  3999. }
  4000. HeapDeleteArray(utf8SrcEndIdx - utf8SrcStartIdx + 2, utf16Buf);
  4001. Output::Print(_u("\n"));
  4002. Output::Print(_u(" Col %4d:%s^\n"), col + 1, ((col+1)<10000) ? _u(" ") : _u(""));
  4003. if (color != 0)
  4004. {
  4005. Output::SetConsoleForeground(color);
  4006. }
  4007. }
  4008. }
  4009. #endif // DBG_DUMP
  4010. /**
  4011. * Get the source code offset for the given <statementIndex>.
  4012. */
  4013. uint FunctionBody::GetStatementStartOffset(const uint statementIndex)
  4014. {
  4015. uint startOffset = 0;
  4016. if (statementIndex != Js::Constants::NoStatementIndex)
  4017. {
  4018. const Js::FunctionBody::SourceInfo * sourceInfo = &(this->m_sourceInfo);
  4019. if (sourceInfo->pSpanSequence != nullptr)
  4020. {
  4021. Js::SmallSpanSequenceIter iter;
  4022. sourceInfo->pSpanSequence->Reset(iter);
  4023. Js::StatementData data;
  4024. sourceInfo->pSpanSequence->Item(statementIndex, iter, data);
  4025. startOffset = data.sourceBegin;
  4026. }
  4027. else
  4028. {
  4029. int index = statementIndex;
  4030. Js::FunctionBody::StatementMap * statementMap = GetNextNonSubexpressionStatementMap(GetStatementMaps(), index);
  4031. startOffset = statementMap->sourceSpan.Begin();
  4032. }
  4033. }
  4034. return startOffset;
  4035. }
  4036. #ifdef IR_VIEWER
  4037. /* BEGIN potentially reusable code */
  4038. /*
  4039. This code could be reused for locating source code in a debugger or to
  4040. retrieve the text of source statements.
  4041. Currently this code is used to retrieve the text of a source code statement
  4042. in the IR_VIEWER feature.
  4043. */
  4044. /**
  4045. * Given a statement's starting offset in the source code, calculate the beginning and end of a statement,
  4046. * as well as the line and column number where the statement appears.
  4047. *
  4048. * @param startOffset (input) The offset into the source code where this statement begins.
  4049. * @param sourceBegin (output) The beginning of the statement in the source string.
  4050. * @param sourceEnd (output) The end of the statement in the source string.
  4051. * @param line (output) The line number where the statement appeared in the source.
  4052. * @param col (output) The column number where the statement appeared in the source.
  4053. */
  4054. void FunctionBody::GetSourceLineFromStartOffset(const uint startOffset, LPCUTF8 *sourceBegin, LPCUTF8 *sourceEnd,
  4055. ULONG * line, LONG * col)
  4056. {
  4057. //
  4058. // get source info
  4059. //
  4060. LPCUTF8 source = GetStartOfDocument(_u("IR Viewer FunctionBody::GetSourceLineFromStartOffset"));
  4061. Utf8SourceInfo* sourceInfo = this->GetUtf8SourceInfo();
  4062. Assert(sourceInfo != nullptr);
  4063. LPCUTF8 sourceInfoSrc = sourceInfo->GetSource(_u("IR Viewer FunctionBody::GetSourceLineFromStartOffset"));
  4064. if (!sourceInfoSrc)
  4065. {
  4066. Assert(sourceInfo->GetIsLibraryCode());
  4067. return;
  4068. }
  4069. if (source != sourceInfoSrc)
  4070. {
  4071. Output::Print(_u("\nDETECTED MISMATCH:\n"));
  4072. Output::Print(_u("GetUtf8SourceInfo()->GetSource(): 0x%08X: %.*s ...\n"), sourceInfo, 16, sourceInfo);
  4073. Output::Print(_u("GetStartOfDocument(): 0x%08X: %.*s ...\n"), source, 16, source);
  4074. AssertMsg(false, "Non-matching start of document");
  4075. }
  4076. //
  4077. // calculate source line info
  4078. //
  4079. size_t cbStartOffset = utf8::CharacterIndexToByteIndex(source, sourceInfo->GetCbLength(), (const charcount_t)startOffset, (size_t)this->m_cbStartOffset, (charcount_t)this->m_cchStartOffset);
  4080. GetLineCharOffsetFromStartChar(startOffset, line, col);
  4081. size_t lastOffset = StartOffset() + LengthInBytes();
  4082. size_t i = 0;
  4083. for (i = cbStartOffset; i < lastOffset && source[i] != '\n' && source[i] != '\r'; i++)
  4084. {
  4085. // do nothing; scan until end of statement
  4086. }
  4087. size_t cbEndOffset = i;
  4088. //
  4089. // return
  4090. //
  4091. *sourceBegin = &source[cbStartOffset];
  4092. *sourceEnd = &source[cbEndOffset];
  4093. }
  4094. /**
  4095. * Given a statement index and output parameters, calculate the beginning and end of a statement,
  4096. * as well as the line and column number where the statement appears.
  4097. *
  4098. * @param statementIndex (input) The statement's index (as used by the StatementBoundary pragma).
  4099. * @param sourceBegin (output) The beginning of the statement in the source string.
  4100. * @param sourceEnd (output) The end of the statement in the source string.
  4101. * @param line (output) The line number where the statement appeared in the source.
  4102. * @param col (output) The column number where the statement appeared in the source.
  4103. */
  4104. void FunctionBody::GetStatementSourceInfo(const uint statementIndex, LPCUTF8 *sourceBegin, LPCUTF8 *sourceEnd,
  4105. ULONG * line, LONG * col)
  4106. {
  4107. const size_t startOffset = GetStatementStartOffset(statementIndex);
  4108. // startOffset should only be 0 if statementIndex is 0, otherwise it is EOF and we should return empty string
  4109. if (startOffset != 0 || statementIndex == 0)
  4110. {
  4111. GetSourceLineFromStartOffset(startOffset, sourceBegin, sourceEnd, line, col);
  4112. }
  4113. else
  4114. {
  4115. *sourceBegin = nullptr;
  4116. *sourceEnd = nullptr;
  4117. *line = 0;
  4118. *col = 0;
  4119. return;
  4120. }
  4121. }
  4122. /* END potentially reusable code */
  4123. #endif /* IR_VIEWER */
  4124. #if ENABLE_TTD
  4125. void FunctionBody::GetSourceLineFromStartOffset_TTD(const uint startOffset, ULONG* line, LONG* col)
  4126. {
  4127. GetLineCharOffsetFromStartChar(startOffset, line, col);
  4128. }
  4129. #endif
  4130. #ifdef IR_VIEWER
  4131. Js::DynamicObject * FunctionBody::GetIRDumpBaseObject()
  4132. {
  4133. if (!this->m_irDumpBaseObject)
  4134. {
  4135. this->m_irDumpBaseObject = this->m_scriptContext->GetLibrary()->CreateObject();
  4136. }
  4137. return this->m_irDumpBaseObject;
  4138. }
  4139. #endif /* IR_VIEWER */
  4140. #if ENABLE_NATIVE_CODEGEN
  4141. #ifdef VTUNE_PROFILING
  4142. #include "jitprofiling.h"
  4143. int EntryPointInfo::GetNativeOffsetMapCount() const
  4144. {
  4145. return this->GetNativeEntryPointData()->GetNativeOffsetMaps().Count();
  4146. }
  4147. uint EntryPointInfo::PopulateLineInfo(void* pInfo, FunctionBody* body)
  4148. {
  4149. auto& nativeOffsetMaps = this->GetNativeEntryPointData()->GetNativeOffsetMaps();
  4150. LineNumberInfo* pLineInfo = (LineNumberInfo*)pInfo;
  4151. ULONG functionLineNumber = body->GetLineNumber();
  4152. pLineInfo[0].Offset = 0;
  4153. pLineInfo[0].LineNumber = functionLineNumber;
  4154. int lineNumber = 0;
  4155. int j = 1; // start with 1 since offset 0 has already been populated with function line number
  4156. int count = nativeOffsetMaps.Count();
  4157. for(int i = 0; i < count; i++)
  4158. {
  4159. const NativeEntryPointData::NativeOffsetMap* map = &nativeOffsetMaps.Item(i);
  4160. uint32 statementIndex = map->statementIndex;
  4161. if (statementIndex == 0)
  4162. {
  4163. // statementIndex is 0, first line in the function, populate with function line number
  4164. pLineInfo[j].Offset = map->nativeOffsetSpan.begin;
  4165. pLineInfo[j].LineNumber = functionLineNumber;
  4166. j++;
  4167. }
  4168. lineNumber = body->GetSourceLineNumber(statementIndex);
  4169. if (lineNumber != 0)
  4170. {
  4171. pLineInfo[j].Offset = map->nativeOffsetSpan.end;
  4172. pLineInfo[j].LineNumber = lineNumber;
  4173. j++;
  4174. }
  4175. }
  4176. return j;
  4177. }
  4178. ULONG FunctionBody::GetSourceLineNumber(uint statementIndex)
  4179. {
  4180. ULONG line = 0;
  4181. if (statementIndex != Js::Constants::NoStatementIndex)
  4182. {
  4183. uint startOffset = GetStartOffset(statementIndex);
  4184. if (startOffset != 0 || statementIndex == 0)
  4185. {
  4186. GetLineCharOffsetFromStartChar(startOffset, &line, nullptr, false /*canAllocateLineCache*/);
  4187. line = line + 1;
  4188. }
  4189. }
  4190. return line;
  4191. }
  4192. uint FunctionBody::GetStartOffset(uint statementIndex) const
  4193. {
  4194. uint startOffset = 0;
  4195. const Js::FunctionBody::SourceInfo * sourceInfo = &this->m_sourceInfo;
  4196. if (sourceInfo->pSpanSequence != nullptr)
  4197. {
  4198. Js::SmallSpanSequenceIter iter;
  4199. sourceInfo->pSpanSequence->Reset(iter);
  4200. Js::StatementData data;
  4201. sourceInfo->pSpanSequence->Item(statementIndex, iter, data);
  4202. startOffset = data.sourceBegin;
  4203. }
  4204. else
  4205. {
  4206. int index = statementIndex;
  4207. Js::FunctionBody::StatementMap * statementMap = GetNextNonSubexpressionStatementMap(GetStatementMaps(), index);
  4208. startOffset = statementMap->sourceSpan.Begin();
  4209. }
  4210. return startOffset;
  4211. }
  4212. #endif
  4213. #endif
  4214. void ParseableFunctionInfo::SetIsNonUserCode(bool set)
  4215. {
  4216. // Mark current function as a non-user code, so that we can distinguish cases where exceptions are
  4217. // caught in non-user code (see ProbeContainer::HasAllowedForException).
  4218. SetFlags(set, Flags_NonUserCode);
  4219. // Propagate setting for all functions in this scope (nested).
  4220. this->ForEachNestedFunc([&](FunctionProxy* proxy, uint32 index)
  4221. {
  4222. ParseableFunctionInfo * pBody = proxy->GetParseableFunctionInfo();
  4223. if (pBody != nullptr)
  4224. {
  4225. pBody->SetIsNonUserCode(set);
  4226. }
  4227. return true;
  4228. });
  4229. }
  4230. void FunctionBody::InsertSymbolToRegSlotList(JsUtil::CharacterBuffer<WCHAR> const& propName, RegSlot reg, RegSlot totalRegsCount)
  4231. {
  4232. if (totalRegsCount > 0)
  4233. {
  4234. PropertyId propertyId = GetOrAddPropertyIdTracked(propName);
  4235. InsertSymbolToRegSlotList(reg, propertyId, totalRegsCount);
  4236. }
  4237. }
  4238. void FunctionBody::InsertSymbolToRegSlotList(RegSlot reg, PropertyId propertyId, RegSlot totalRegsCount)
  4239. {
  4240. if (totalRegsCount > 0)
  4241. {
  4242. if (this->GetPropertyIdOnRegSlotsContainer() == nullptr)
  4243. {
  4244. this->SetPropertyIdOnRegSlotsContainer(PropertyIdOnRegSlotsContainer::New(m_scriptContext->GetRecycler()));
  4245. }
  4246. if (this->GetPropertyIdOnRegSlotsContainer()->propertyIdsForRegSlots == nullptr)
  4247. {
  4248. this->GetPropertyIdOnRegSlotsContainer()->CreateRegSlotsArray(m_scriptContext->GetRecycler(), totalRegsCount);
  4249. }
  4250. Assert(this->GetPropertyIdOnRegSlotsContainer() != nullptr);
  4251. this->GetPropertyIdOnRegSlotsContainer()->Insert(reg, propertyId);
  4252. }
  4253. }
  4254. void FunctionBody::SetPropertyIdsOfFormals(PropertyIdArray * formalArgs)
  4255. {
  4256. Assert(formalArgs);
  4257. if (this->GetPropertyIdOnRegSlotsContainer() == nullptr)
  4258. {
  4259. this->SetPropertyIdOnRegSlotsContainer(PropertyIdOnRegSlotsContainer::New(m_scriptContext->GetRecycler()));
  4260. }
  4261. this->GetPropertyIdOnRegSlotsContainer()->SetFormalArgs(formalArgs);
  4262. }
  4263. #ifdef ENABLE_SCRIPT_PROFILING
  4264. HRESULT FunctionBody::RegisterFunction(BOOL fChangeMode, BOOL fOnlyCurrent)
  4265. {
  4266. if (!this->IsFunctionParsed())
  4267. {
  4268. return S_OK;
  4269. }
  4270. HRESULT hr = this->ReportFunctionCompiled();
  4271. if (FAILED(hr))
  4272. {
  4273. return hr;
  4274. }
  4275. if (fChangeMode)
  4276. {
  4277. this->SetEntryToProfileMode();
  4278. }
  4279. if (!fOnlyCurrent)
  4280. {
  4281. for (uint uIndex = 0; uIndex < this->GetNestedCount(); uIndex++)
  4282. {
  4283. Js::ParseableFunctionInfo * pBody = this->GetNestedFunctionForExecution(uIndex);
  4284. if (pBody == nullptr || !pBody->IsFunctionParsed())
  4285. {
  4286. continue;
  4287. }
  4288. hr = pBody->GetFunctionBody()->RegisterFunction(fChangeMode);
  4289. if (FAILED(hr))
  4290. {
  4291. break;
  4292. }
  4293. }
  4294. }
  4295. return hr;
  4296. }
  4297. HRESULT FunctionBody::ReportScriptCompiled()
  4298. {
  4299. AssertMsg(m_scriptContext != nullptr, "Script Context is null when reporting function information");
  4300. PROFILER_SCRIPT_TYPE type = IsDynamicScript() ? PROFILER_SCRIPT_TYPE_DYNAMIC : PROFILER_SCRIPT_TYPE_USER;
  4301. IDebugDocumentContext *pDebugDocumentContext = nullptr;
  4302. this->m_scriptContext->GetDocumentContext(this, &pDebugDocumentContext);
  4303. HRESULT hr = m_scriptContext->OnScriptCompiled((PROFILER_TOKEN) this->GetUtf8SourceInfo()->GetSourceInfoId(), type, pDebugDocumentContext);
  4304. RELEASEPTR(pDebugDocumentContext);
  4305. return hr;
  4306. }
  4307. HRESULT FunctionBody::ReportFunctionCompiled()
  4308. {
  4309. // Some assumptions by Logger interface.
  4310. // to send NULL as a name in case the name is anonymous and hint is anonymous code.
  4311. const char16 *pwszName = GetExternalDisplayName();
  4312. IDebugDocumentContext *pDebugDocumentContext = nullptr;
  4313. this->m_scriptContext->GetDocumentContext(this, &pDebugDocumentContext);
  4314. SetHasFunctionCompiledSent(true);
  4315. HRESULT hr = m_scriptContext->OnFunctionCompiled(m_functionNumber, (PROFILER_TOKEN) this->GetUtf8SourceInfo()->GetSourceInfoId(), pwszName, nullptr, pDebugDocumentContext);
  4316. RELEASEPTR(pDebugDocumentContext);
  4317. #if DBG
  4318. if (m_iProfileSession >= m_scriptContext->GetProfileSession())
  4319. {
  4320. OUTPUT_TRACE_DEBUGONLY(Js::ScriptProfilerPhase, _u("FunctionBody::ReportFunctionCompiled, Duplicate compile event (%d < %d) for FunctionNumber : %d\n"),
  4321. m_iProfileSession, m_scriptContext->GetProfileSession(), m_functionNumber);
  4322. }
  4323. AssertMsg(m_iProfileSession < m_scriptContext->GetProfileSession(), "Duplicate compile event sent");
  4324. m_iProfileSession = m_scriptContext->GetProfileSession();
  4325. #endif
  4326. return hr;
  4327. }
  4328. void FunctionBody::SetEntryToProfileMode()
  4329. {
  4330. #if ENABLE_NATIVE_CODEGEN
  4331. AssertMsg(this->m_scriptContext->CurrentThunk == ProfileEntryThunk, "ScriptContext not in profile mode");
  4332. #if DBG
  4333. AssertMsg(m_iProfileSession == m_scriptContext->GetProfileSession(), "Changing mode to profile for function that didn't send compile event");
  4334. #endif
  4335. // This is always done when bg thread is paused hence we don't need any kind of thread-synchronization at this point.
  4336. // Change entry points to Profile Thunk
  4337. // If the entrypoint is CodeGenOnDemand or CodeGen - then we don't change the entry points
  4338. ProxyEntryPointInfo* defaultEntryPointInfo = this->GetDefaultEntryPointInfo();
  4339. if (!IsIntermediateCodeGenThunk(defaultEntryPointInfo->jsMethod)
  4340. && defaultEntryPointInfo->jsMethod != DynamicProfileInfo::EnsureDynamicProfileInfoThunk)
  4341. {
  4342. if (this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredParsingThunk)
  4343. {
  4344. defaultEntryPointInfo->jsMethod = ProfileDeferredParsingThunk;
  4345. }
  4346. else if (this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredDeserializeThunk)
  4347. {
  4348. defaultEntryPointInfo->jsMethod = ProfileDeferredDeserializeThunk;
  4349. }
  4350. else
  4351. {
  4352. defaultEntryPointInfo->jsMethod = ProfileEntryThunk;
  4353. }
  4354. }
  4355. // Update old entry points on the deferred prototype type so that they match current defaultEntryPointInfo.
  4356. // to make sure that new JavascriptFunction instances use profile thunk.
  4357. if (this->deferredPrototypeType)
  4358. {
  4359. this->deferredPrototypeType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
  4360. this->deferredPrototypeType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4361. }
  4362. if (this->undeferredFunctionType)
  4363. {
  4364. this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
  4365. this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4366. }
  4367. if (this->crossSiteDeferredFunctionType)
  4368. {
  4369. this->crossSiteDeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4370. }
  4371. if (this->crossSiteUndeferredFunctionType)
  4372. {
  4373. this->crossSiteUndeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4374. }
  4375. #if DBG
  4376. if (!this->HasValidEntryPoint())
  4377. {
  4378. OUTPUT_TRACE_DEBUGONLY(Js::ScriptProfilerPhase, _u("FunctionBody::SetEntryToProfileMode, Assert due to HasValidEntryPoint(), directEntrypoint : 0x%0IX, originalentrypoint : 0x%0IX\n"),
  4379. this->GetDefaultEntryPointInfo()->jsMethod, this->GetOriginalEntryPoint());
  4380. AssertMsg(false, "Not a valid EntryPoint");
  4381. }
  4382. #endif
  4383. #endif //ENABLE_NATIVE_CODEGEN
  4384. }
  4385. #endif // ENABLE_SCRIPT_PROFILING
  4386. #if DBG
  4387. void FunctionBody::MustBeInDebugMode()
  4388. {
  4389. Assert(GetUtf8SourceInfo()->IsInDebugMode());
  4390. Assert(m_sourceInfo.pSpanSequence == nullptr);
  4391. Assert(this->GetStatementMaps() != nullptr);
  4392. }
  4393. #endif
  4394. void ParseableFunctionInfo::CleanupToReparse()
  4395. {
  4396. #if DBG
  4397. if (this->IsFunctionBody())
  4398. {
  4399. GetFunctionBody()->UnlockCounters();
  4400. }
  4401. #endif
  4402. // The current function is already compiled. In order to prep this function to ready for debug mode, most of the previous information need to be thrown away.
  4403. // Clean up the nested functions
  4404. this->ForEachNestedFunc([&](FunctionProxy* proxy, uint32 index)
  4405. {
  4406. // Note: redeferred functions may have fully compiled children. If we find a redeferred function, keep walking.
  4407. if (proxy && ((proxy->CanBeDeferred() && proxy->GetFunctionInfo()->GetCompileCount() > 0) || proxy->IsFunctionBody()))
  4408. {
  4409. proxy->GetParseableFunctionInfo()->CleanupToReparse();
  4410. }
  4411. return true;
  4412. });
  4413. this->CleanupToReparseHelper();
  4414. if (this->IsFunctionBody())
  4415. {
  4416. this->GetFunctionBody()->CleanupToReparseHelper();
  4417. }
  4418. }
  4419. void FunctionBody::CleanupToReparseHelper()
  4420. {
  4421. this->CleanupRecyclerData(/* isShutdown */ false, true /* capture entry point cleanup stack trace */);
  4422. this->entryPoints->ClearAndZero();
  4423. // Store the originalEntryPoint to restore it back immediately.
  4424. this->CreateNewDefaultEntryPoint();
  4425. this->SetOriginalEntryPoint(this->GetScriptContext()->CurrentThunk);
  4426. if (this->m_defaultEntryPointInfo)
  4427. {
  4428. this->GetDefaultFunctionEntryPointInfo()->entryPointIndex = 0;
  4429. }
  4430. this->SetAuxiliaryData(nullptr);
  4431. this->SetAuxiliaryContextData(nullptr);
  4432. AssertMsg(!this->byteCodeBlock || !this->IsWasmFunction(), "We should never reset the bytecode block for Wasm");
  4433. this->byteCodeBlock = nullptr;
  4434. this->SetLoopHeaderArray(nullptr);
  4435. this->SetConstTable(nullptr);
  4436. this->SetCodeGenRuntimeData(nullptr);
  4437. this->cacheIdToPropertyIdMap = nullptr;
  4438. this->SetFormalsPropIdArray(nullptr);
  4439. this->SetReferencedPropertyIdMap(nullptr);
  4440. #if ENABLE_NATIVE_CODEGEN
  4441. this->SetCallSiteToCallApplyCallSiteArray(nullptr);
  4442. #endif
  4443. this->SetLiteralRegexs(nullptr);
  4444. this->SetSlotIdInCachedScopeToNestedIndexArray(nullptr);
  4445. this->SetStatementMaps(nullptr);
  4446. this->SetCodeGenGetSetRuntimeData(nullptr);
  4447. this->SetPropertyIdOnRegSlotsContainer(nullptr);
  4448. this->profiledLdLenCount = 0;
  4449. this->profiledLdElemCount = 0;
  4450. this->profiledStElemCount = 0;
  4451. this->profiledCallSiteCount = 0;
  4452. this->profiledArrayCallSiteCount = 0;
  4453. this->profiledDivOrRemCount = 0;
  4454. this->profiledSwitchCount = 0;
  4455. this->profiledReturnTypeCount = 0;
  4456. this->profiledSlotCount = 0;
  4457. this->SetLoopCount(0);
  4458. this->m_envDepth = (uint16)-1;
  4459. this->SetByteCodeCount(0);
  4460. this->SetByteCodeWithoutLDACount(0);
  4461. this->SetByteCodeInLoopCount(0);
  4462. #if ENABLE_PROFILE_INFO
  4463. if (this->dynamicProfileInfo != nullptr)
  4464. {
  4465. SourceContextInfo * sourceContextInfo = GetSourceContextInfo();
  4466. if(sourceContextInfo && sourceContextInfo->sourceDynamicProfileManager)
  4467. {
  4468. sourceContextInfo->sourceDynamicProfileManager->RemoveDynamicProfileInfo(GetFunctionInfo()->GetLocalFunctionId());
  4469. }
  4470. #ifdef DYNAMIC_PROFILE_STORAGE
  4471. DynamicProfileInfoList * profileInfoList = GetScriptContext()->GetProfileInfoList();
  4472. if (profileInfoList)
  4473. {
  4474. FOREACH_SLISTBASE_ENTRY_EDITING(Field(DynamicProfileInfo*), info, profileInfoList, iter)
  4475. {
  4476. if (info->HasFunctionBody() && info->GetFunctionBody() == this)
  4477. {
  4478. iter.UnlinkCurrent();
  4479. break;
  4480. }
  4481. }
  4482. NEXT_SLISTBASE_ENTRY_EDITING;
  4483. }
  4484. #endif
  4485. this->dynamicProfileInfo = nullptr;
  4486. }
  4487. #endif
  4488. this->hasExecutionDynamicProfileInfo = false;
  4489. this->SetFirstTmpRegister(Constants::NoRegister);
  4490. this->SetVarCount(0);
  4491. this->SetConstantCount(0);
  4492. this->SetLocalClosureRegister(Constants::NoRegister);
  4493. this->SetParamClosureRegister(Constants::NoRegister);
  4494. this->SetLocalFrameDisplayRegister(Constants::NoRegister);
  4495. this->SetEnvRegister(Constants::NoRegister);
  4496. this->SetThisRegisterForEventHandler(Constants::NoRegister);
  4497. this->SetFirstInnerScopeRegister(Constants::NoRegister);
  4498. this->SetFuncExprScopeRegister(Constants::NoRegister);
  4499. this->SetInnerScopeCount(0);
  4500. this->hasCachedScopePropIds = false;
  4501. this->ResetObjectLiteralTypes();
  4502. this->SetInlineCacheCount(0);
  4503. this->SetRootObjectLoadInlineCacheStart(0);
  4504. this->SetRootObjectLoadMethodInlineCacheStart(0);
  4505. this->SetRootObjectStoreInlineCacheStart(0);
  4506. this->SetIsInstInlineCacheCount(0);
  4507. this->m_inlineCachesOnFunctionObject = false;
  4508. this->SetReferencedPropertyIdCount(0);
  4509. #if ENABLE_PROFILE_INFO
  4510. this->SetPolymorphicCallSiteInfoHead(nullptr);
  4511. #endif
  4512. this->executionState.SetInterpretedCount(0);
  4513. this->m_hasDoneAllNonLocalReferenced = false;
  4514. this->SetDebuggerScopeIndex(0);
  4515. this->m_isAsmJsScheduledForFullJIT = false;
  4516. this->m_asmJsTotalLoopCount = 0;
  4517. recentlyBailedOutOfJittedLoopBody = false;
  4518. SetLoopInterpreterLimit(CONFIG_FLAG(LoopInterpretCount));
  4519. ReinitializeExecutionModeAndLimits();
  4520. Assert(this->m_sourceInfo.m_probeCount == 0);
  4521. this->m_sourceInfo.m_probeBackingBlock = nullptr;
  4522. #if DBG
  4523. // This could be non-zero if the function threw exception before. Reset it.
  4524. this->m_DEBUG_executionCount = 0;
  4525. #endif
  4526. if (this->m_sourceInfo.pSpanSequence != nullptr)
  4527. {
  4528. HeapDelete(this->m_sourceInfo.pSpanSequence);
  4529. this->m_sourceInfo.pSpanSequence = nullptr;
  4530. }
  4531. if (this->m_sourceInfo.m_auxStatementData != nullptr)
  4532. {
  4533. // This must be consistent with how we allocate the data for this and inner structures.
  4534. // We are using recycler, thus it's enough just to set to NULL.
  4535. Assert(m_scriptContext->GetRecycler()->IsValidObject(m_sourceInfo.m_auxStatementData));
  4536. m_sourceInfo.m_auxStatementData = nullptr;
  4537. }
  4538. }
  4539. void ParseableFunctionInfo::CleanupToReparseHelper()
  4540. {
  4541. #if DYNAMIC_INTERPRETER_THUNK
  4542. if (m_isAsmJsFunction && m_dynamicInterpreterThunk)
  4543. {
  4544. m_scriptContext->ReleaseDynamicAsmJsInterpreterThunk((BYTE*)this->m_dynamicInterpreterThunk, true);
  4545. this->m_dynamicInterpreterThunk = nullptr;
  4546. }
  4547. #endif
  4548. this->SetScopeInfo(nullptr);
  4549. this->SetPropertyIdsForScopeSlotArray(nullptr, 0);
  4550. this->GetUtf8SourceInfo()->DeleteLineOffsetCache();
  4551. // Reset to default.
  4552. this->flags = this->IsClassConstructor() ? Flags_None : Flags_HasNoExplicitReturnValue;
  4553. ResetInParams();
  4554. this->m_isAsmjsMode = false;
  4555. this->m_isAsmJsFunction = false;
  4556. }
  4557. #ifdef ENABLE_SCRIPT_DEBUGGING
  4558. void FunctionBody::SetEntryToDeferParseForDebugger()
  4559. {
  4560. ProxyEntryPointInfo* defaultEntryPointInfo = this->GetDefaultEntryPointInfo();
  4561. if (defaultEntryPointInfo->jsMethod != DefaultDeferredParsingThunk
  4562. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  4563. && defaultEntryPointInfo->jsMethod != ProfileDeferredParsingThunk
  4564. #endif
  4565. )
  4566. {
  4567. #if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
  4568. // Just change the thunk, the cleanup will be done once the function gets called.
  4569. if (this->m_scriptContext->CurrentThunk == ProfileEntryThunk)
  4570. {
  4571. defaultEntryPointInfo->jsMethod = ProfileDeferredParsingThunk;
  4572. }
  4573. else
  4574. #endif
  4575. {
  4576. defaultEntryPointInfo->jsMethod = DefaultDeferredParsingThunk;
  4577. }
  4578. this->SetOriginalEntryPoint(DefaultDeferredParsingThunk);
  4579. this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
  4580. }
  4581. // Set other state back to before parse as well
  4582. this->SetStackNestedFunc(false);
  4583. this->SetAuxPtr<AuxPointerType::StackNestedFuncParent>(nullptr);
  4584. this->SetReparsed(true);
  4585. #if DBG
  4586. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  4587. OUTPUT_VERBOSE_TRACE(Js::DebuggerPhase, _u("Regenerate Due To Debug Mode: function %s (%s) from script context %p\n"),
  4588. this->GetDisplayName(), this->GetDebugNumberSet(debugStringBuffer), m_scriptContext);
  4589. this->UnlockCounters(); // assuming background jit is stopped and allow the counter setters access again
  4590. #endif
  4591. }
  4592. #endif
  4593. void FunctionBody::ClearEntryPoints()
  4594. {
  4595. if (this->entryPoints)
  4596. {
  4597. this->MapEntryPoints([] (int index, FunctionEntryPointInfo* entryPoint)
  4598. {
  4599. if (nullptr != entryPoint)
  4600. {
  4601. // Finalize = Free up work item if it hasn't been released yet + entry point clean up
  4602. // isShutdown is false because cleanup is called only in the !isShutdown case
  4603. entryPoint->Finalize(/*isShutdown*/ false);
  4604. }
  4605. });
  4606. this->MapLoopHeaders([] (uint loopNumber, LoopHeader* header)
  4607. {
  4608. header->MapEntryPoints([] (int index, LoopEntryPointInfo* entryPoint)
  4609. {
  4610. entryPoint->Cleanup(/*isShutdown*/ false, true /* capture cleanup stack */);
  4611. });
  4612. });
  4613. }
  4614. this->entryPoints->ClearAndZero();
  4615. }
  4616. //
  4617. // For library code all references to jitted entry points need to be removed
  4618. //
  4619. void FunctionBody::ResetEntryPoint()
  4620. {
  4621. ClearEntryPoints();
  4622. this->CreateNewDefaultEntryPoint();
  4623. this->SetOriginalEntryPoint(DefaultEntryThunk);
  4624. m_defaultEntryPointInfo->jsMethod = m_scriptContext->CurrentThunk;
  4625. if (this->deferredPrototypeType)
  4626. {
  4627. // Update old entry points on the deferred prototype type,
  4628. // as they may point to old native code gen regions which are gone now.
  4629. this->deferredPrototypeType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
  4630. this->deferredPrototypeType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4631. }
  4632. if (this->undeferredFunctionType)
  4633. {
  4634. this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
  4635. this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4636. }
  4637. if (this->crossSiteDeferredFunctionType)
  4638. {
  4639. this->crossSiteDeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4640. }
  4641. if (this->crossSiteUndeferredFunctionType)
  4642. {
  4643. this->crossSiteUndeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
  4644. }
  4645. ReinitializeExecutionModeAndLimits();
  4646. }
  4647. void FunctionBody::AddDeferParseAttribute()
  4648. {
  4649. this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
  4650. }
  4651. void FunctionBody::RemoveDeferParseAttribute()
  4652. {
  4653. this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() & (~FunctionInfo::Attributes::DeferredParse)));
  4654. }
  4655. Js::DebuggerScope * FunctionBody::GetDiagCatchScopeObjectAt(int byteCodeOffset)
  4656. {
  4657. if (GetScopeObjectChain())
  4658. {
  4659. for (int i = 0; i < GetScopeObjectChain()->pScopeChain->Count(); i++)
  4660. {
  4661. Js::DebuggerScope *debuggerScope = GetScopeObjectChain()->pScopeChain->Item(i);
  4662. Assert(debuggerScope);
  4663. if (debuggerScope->IsCatchScope() && debuggerScope->IsOffsetInScope(byteCodeOffset))
  4664. {
  4665. return debuggerScope;
  4666. }
  4667. }
  4668. }
  4669. return nullptr;
  4670. }
  4671. ushort SmallSpanSequence::GetDiff(int current, int prev)
  4672. {
  4673. int diff = current - prev;
  4674. if ((diff) < SHRT_MIN || (diff) >= SHRT_MAX)
  4675. {
  4676. diff = SHRT_MAX;
  4677. if (!this->pActualOffsetList)
  4678. {
  4679. this->pActualOffsetList = JsUtil::GrowingUint32HeapArray::Create(4);
  4680. }
  4681. this->pActualOffsetList->Add(current);
  4682. }
  4683. return (ushort)diff;
  4684. }
  4685. // Get Values of the beginning of the statement at particular index.
  4686. BOOL SmallSpanSequence::GetRangeAt(int index, SmallSpanSequenceIter &iter, int * pCountOfMissed, StatementData & data)
  4687. {
  4688. Assert((uint32)index < pStatementBuffer->Count());
  4689. SmallSpan span(pStatementBuffer->ItemInBuffer((uint32)index));
  4690. int countOfMissed = 0;
  4691. if ((short)span.sourceBegin == SHRT_MAX)
  4692. {
  4693. // Look in ActualOffset store
  4694. Assert(this->pActualOffsetList);
  4695. Assert(this->pActualOffsetList->Count() > 0);
  4696. Assert(this->pActualOffsetList->Count() > (uint32)iter.indexOfActualOffset);
  4697. data.sourceBegin = this->pActualOffsetList->ItemInBuffer((uint32)iter.indexOfActualOffset);
  4698. countOfMissed++;
  4699. }
  4700. else
  4701. {
  4702. data.sourceBegin = iter.accumulatedSourceBegin + (short)span.sourceBegin;
  4703. }
  4704. if (span.bytecodeBegin == SHRT_MAX)
  4705. {
  4706. // Look in ActualOffset store
  4707. Assert(this->pActualOffsetList);
  4708. Assert(this->pActualOffsetList->Count() > 0);
  4709. Assert(this->pActualOffsetList->Count() > (uint32)(iter.indexOfActualOffset + countOfMissed));
  4710. data.bytecodeBegin = this->pActualOffsetList->ItemInBuffer((uint32)iter.indexOfActualOffset + countOfMissed);
  4711. countOfMissed++;
  4712. }
  4713. else
  4714. {
  4715. data.bytecodeBegin = iter.accumulatedBytecodeBegin + span.bytecodeBegin;
  4716. }
  4717. if (pCountOfMissed)
  4718. {
  4719. *pCountOfMissed = countOfMissed;
  4720. }
  4721. return TRUE;
  4722. }
  4723. void SmallSpanSequence::Reset(SmallSpanSequenceIter &iter)
  4724. {
  4725. iter.accumulatedIndex = 0;
  4726. iter.accumulatedSourceBegin = baseValue;
  4727. iter.accumulatedBytecodeBegin = 0;
  4728. iter.indexOfActualOffset = 0;
  4729. }
  4730. BOOL SmallSpanSequence::GetMatchingStatementFromBytecode(int bytecode, SmallSpanSequenceIter &iter, StatementData & data)
  4731. {
  4732. if (Count() > 0 && bytecode >= 0)
  4733. {
  4734. // Support only in forward direction
  4735. if (bytecode < iter.accumulatedBytecodeBegin
  4736. || iter.accumulatedIndex <= 0 || (uint32)iter.accumulatedIndex >= Count())
  4737. {
  4738. // re-initialize the accumulators
  4739. Reset(iter);
  4740. }
  4741. while ((uint32)iter.accumulatedIndex < Count())
  4742. {
  4743. int countOfMissed = 0;
  4744. if (!GetRangeAt(iter.accumulatedIndex, iter, &countOfMissed, data))
  4745. {
  4746. Assert(FALSE);
  4747. break;
  4748. }
  4749. if (data.bytecodeBegin >= bytecode)
  4750. {
  4751. if (data.bytecodeBegin > bytecode)
  4752. {
  4753. // Not exactly at the current bytecode, so it falls in between previous statement.
  4754. data.sourceBegin = iter.accumulatedSourceBegin;
  4755. data.bytecodeBegin = iter.accumulatedBytecodeBegin;
  4756. }
  4757. return TRUE;
  4758. }
  4759. // Look for the next
  4760. iter.accumulatedSourceBegin = data.sourceBegin;
  4761. iter.accumulatedBytecodeBegin = data.bytecodeBegin;
  4762. iter.accumulatedIndex++;
  4763. if (countOfMissed)
  4764. {
  4765. iter.indexOfActualOffset += countOfMissed;
  4766. }
  4767. }
  4768. if (iter.accumulatedIndex != -1)
  4769. {
  4770. // Give the last one.
  4771. Assert(data.bytecodeBegin < bytecode);
  4772. return TRUE;
  4773. }
  4774. }
  4775. // Failed to give the correct one, init to default
  4776. iter.accumulatedIndex = -1;
  4777. return FALSE;
  4778. }
  4779. BOOL SmallSpanSequence::Item(int index, SmallSpanSequenceIter &iter, StatementData & data)
  4780. {
  4781. if (!pStatementBuffer || (uint32)index >= pStatementBuffer->Count())
  4782. {
  4783. return FALSE;
  4784. }
  4785. if (iter.accumulatedIndex <= 0 || iter.accumulatedIndex > index)
  4786. {
  4787. Reset(iter);
  4788. }
  4789. while (iter.accumulatedIndex <= index)
  4790. {
  4791. Assert((uint32)iter.accumulatedIndex < pStatementBuffer->Count());
  4792. int countOfMissed = 0;
  4793. if (!GetRangeAt(iter.accumulatedIndex, iter, &countOfMissed, data))
  4794. {
  4795. Assert(FALSE);
  4796. break;
  4797. }
  4798. // We store the next index
  4799. iter.accumulatedSourceBegin = data.sourceBegin;
  4800. iter.accumulatedBytecodeBegin = data.bytecodeBegin;
  4801. iter.accumulatedIndex++;
  4802. if (countOfMissed)
  4803. {
  4804. iter.indexOfActualOffset += countOfMissed;
  4805. }
  4806. if ((iter.accumulatedIndex - 1) == index)
  4807. {
  4808. return TRUE;
  4809. }
  4810. }
  4811. return FALSE;
  4812. }
  4813. BOOL SmallSpanSequence::Seek(int index, StatementData & data)
  4814. {
  4815. // This method will not alter any state of the variables, so this will just do plain search
  4816. // from the beginning to look for that index.
  4817. SmallSpanSequenceIter iter;
  4818. Reset(iter);
  4819. return Item(index, iter, data);
  4820. }
  4821. PropertyIdOnRegSlotsContainer * PropertyIdOnRegSlotsContainer::New(Recycler * recycler)
  4822. {
  4823. return RecyclerNew(recycler, PropertyIdOnRegSlotsContainer);
  4824. }
  4825. PropertyIdOnRegSlotsContainer::PropertyIdOnRegSlotsContainer()
  4826. : propertyIdsForRegSlots(nullptr), length(0), propertyIdsForFormalArgs(nullptr), formalsUpperBound(Js::Constants::NoRegister)
  4827. {
  4828. }
  4829. void PropertyIdOnRegSlotsContainer::CreateRegSlotsArray(Recycler * recycler, uint _length)
  4830. {
  4831. Assert(propertyIdsForRegSlots == nullptr);
  4832. propertyIdsForRegSlots = RecyclerNewArrayLeafZ(recycler, PropertyId, _length);
  4833. length = _length;
  4834. }
  4835. void PropertyIdOnRegSlotsContainer::SetFormalArgs(PropertyIdArray * formalArgs)
  4836. {
  4837. propertyIdsForFormalArgs = formalArgs;
  4838. }
  4839. //
  4840. // Helper methods for PropertyIdOnRegSlotsContainer
  4841. void PropertyIdOnRegSlotsContainer::Insert(RegSlot reg, PropertyId propId)
  4842. {
  4843. //
  4844. // Reg is being used as an index;
  4845. Assert(propertyIdsForRegSlots);
  4846. Assert(reg < length);
  4847. //
  4848. // the current reg is unaccounted for const reg count. while fetching calculate the actual regslot value.
  4849. Assert(propertyIdsForRegSlots[reg] == 0 || propertyIdsForRegSlots[reg] == propId);
  4850. propertyIdsForRegSlots[reg] = propId;
  4851. }
  4852. void PropertyIdOnRegSlotsContainer::FetchItemAt(uint index, FunctionBody *pFuncBody, __out PropertyId *pPropId, __out RegSlot *pRegSlot)
  4853. {
  4854. Assert(index < length);
  4855. Assert(pPropId);
  4856. Assert(pRegSlot);
  4857. Assert(pFuncBody);
  4858. *pPropId = propertyIdsForRegSlots[index];
  4859. *pRegSlot = pFuncBody->MapRegSlot(index);
  4860. }
  4861. bool PropertyIdOnRegSlotsContainer::IsRegSlotFormal(RegSlot reg)
  4862. {
  4863. if (propertyIdsForFormalArgs != nullptr && reg < length)
  4864. {
  4865. PropertyId propId = propertyIdsForRegSlots[reg];
  4866. for (uint32 i = 0; i < propertyIdsForFormalArgs->count; i++)
  4867. {
  4868. if (propertyIdsForFormalArgs->elements[i] == propId)
  4869. {
  4870. return true;
  4871. }
  4872. }
  4873. }
  4874. return false;
  4875. }
  4876. ScopeType FrameDisplay::GetScopeType(void* scope)
  4877. {
  4878. if(Js::VarIs<Js::ActivationObject>(scope))
  4879. {
  4880. return ScopeType_ActivationObject;
  4881. }
  4882. if(Js::ScopeSlots::Is(scope))
  4883. {
  4884. return ScopeType_SlotArray;
  4885. }
  4886. return ScopeType_WithScope;
  4887. }
  4888. // ScopeSlots
  4889. bool ScopeSlots::IsDebuggerScopeSlotArray()
  4890. {
  4891. return DebuggerScope::Is(slotArray[ScopeMetadataSlotIndex]);
  4892. }
  4893. // DebuggerScope
  4894. bool DebuggerScope::Is(void* ptr)
  4895. {
  4896. if (!ptr)
  4897. {
  4898. return false;
  4899. }
  4900. return VirtualTableInfo<DebuggerScope>::HasVirtualTable(ptr);
  4901. }
  4902. // Get the sibling for the current debugger scope.
  4903. DebuggerScope * DebuggerScope::GetSiblingScope(RegSlot location, FunctionBody *functionBody)
  4904. {
  4905. bool isBlockSlotOrObject = scopeType == Js::DiagExtraScopesType::DiagBlockScopeInSlot || scopeType == Js::DiagExtraScopesType::DiagBlockScopeInObject;
  4906. bool isCatchSlotOrObject = scopeType == Js::DiagExtraScopesType::DiagCatchScopeInSlot || scopeType == Js::DiagExtraScopesType::DiagCatchScopeInObject;
  4907. // This is expected to be called only when the current scope is either slot or activation object.
  4908. Assert(isBlockSlotOrObject || isCatchSlotOrObject);
  4909. if (siblingScope == nullptr)
  4910. {
  4911. // If the sibling isn't there, attempt to retrieve it if we're reparsing or create it anew if this is the first parse.
  4912. siblingScope = functionBody->RecordStartScopeObject(isBlockSlotOrObject ? Js::DiagExtraScopesType::DiagBlockScopeDirect : Js::DiagExtraScopesType::DiagCatchScopeDirect, GetStart(), location);
  4913. }
  4914. return siblingScope;
  4915. }
  4916. // Adds a new property to be tracked in the debugger scope.
  4917. // location - The slot array index or register slot location of where the property is stored.
  4918. // propertyId - The property ID of the property.
  4919. // flags - Flags that help describe the property.
  4920. void DebuggerScope::AddProperty(RegSlot location, Js::PropertyId propertyId, DebuggerScopePropertyFlags flags)
  4921. {
  4922. DebuggerScopeProperty scopeProperty;
  4923. scopeProperty.location = location;
  4924. scopeProperty.propId = propertyId;
  4925. // This offset is uninitialized until the property is initialized (with a ld opcode, for example).
  4926. scopeProperty.byteCodeInitializationOffset = Constants::InvalidByteCodeOffset;
  4927. scopeProperty.flags = flags;
  4928. // Delay allocate the property list so we don't take up memory if there are no properties in this scope.
  4929. // Scopes are created during non-debug mode as well so we want to keep them as small as possible.
  4930. this->EnsurePropertyListIsAllocated();
  4931. // The property doesn't exist yet, so add it.
  4932. this->scopeProperties->Add(scopeProperty);
  4933. }
  4934. bool DebuggerScope::HasProperty(Js::PropertyId propertyId)
  4935. {
  4936. int i = -1;
  4937. return GetPropertyIndex(propertyId, i);
  4938. }
  4939. bool DebuggerScope::GetPropertyIndex(Js::PropertyId propertyId, int& index)
  4940. {
  4941. if (!this->HasProperties())
  4942. {
  4943. index = -1;
  4944. return false;
  4945. }
  4946. bool found = this->scopeProperties->MapUntil( [&](int i, const DebuggerScopeProperty& scopeProperty) {
  4947. if(scopeProperty.propId == propertyId)
  4948. {
  4949. index = scopeProperty.location;
  4950. return true;
  4951. }
  4952. return false;
  4953. });
  4954. if(!found)
  4955. {
  4956. return false;
  4957. }
  4958. return true;
  4959. }
  4960. #if DBG
  4961. void DebuggerScope::Dump()
  4962. {
  4963. int indent = (GetScopeDepth() - 1) * 4;
  4964. Output::Print(indent, _u("Begin scope: Address: %p Type: %s Location: %d Sibling: %p Range: [%d, %d]\n "), this, GetDebuggerScopeTypeString(scopeType), scopeLocation, PointerValue(this->siblingScope), range.begin, range.end);
  4965. if (this->HasProperties())
  4966. {
  4967. this->scopeProperties->Map( [=] (int i, Js::DebuggerScopeProperty& scopeProperty) {
  4968. Output::Print(indent, _u("%s(%d) Location: %d Const: %s Initialized: %d\n"), ThreadContext::GetContextForCurrentThread()->GetPropertyName(scopeProperty.propId)->GetBuffer(),
  4969. scopeProperty.propId, scopeProperty.location, scopeProperty.IsConst() ? _u("true"): _u("false"), scopeProperty.byteCodeInitializationOffset);
  4970. });
  4971. }
  4972. Output::Print(_u("\n"));
  4973. }
  4974. // Returns the debugger scope type in string format.
  4975. PCWSTR DebuggerScope::GetDebuggerScopeTypeString(DiagExtraScopesType scopeType)
  4976. {
  4977. switch (scopeType)
  4978. {
  4979. case DiagExtraScopesType::DiagBlockScopeDirect:
  4980. return _u("DiagBlockScopeDirect");
  4981. case DiagExtraScopesType::DiagBlockScopeInObject:
  4982. return _u("DiagBlockScopeInObject");
  4983. case DiagExtraScopesType::DiagBlockScopeInSlot:
  4984. return _u("DiagBlockScopeInSlot");
  4985. case DiagExtraScopesType::DiagBlockScopeRangeEnd:
  4986. return _u("DiagBlockScopeRangeEnd");
  4987. case DiagExtraScopesType::DiagCatchScopeDirect:
  4988. return _u("DiagCatchScopeDirect");
  4989. case DiagExtraScopesType::DiagCatchScopeInObject:
  4990. return _u("DiagCatchScopeInObject");
  4991. case DiagExtraScopesType::DiagCatchScopeInSlot:
  4992. return _u("DiagCatchScopeInSlot");
  4993. case DiagExtraScopesType::DiagUnknownScope:
  4994. return _u("DiagUnknownScope");
  4995. case DiagExtraScopesType::DiagWithScope:
  4996. return _u("DiagWithScope");
  4997. case DiagExtraScopesType::DiagParamScope:
  4998. return _u("DiagParamScope");
  4999. case DiagExtraScopesType::DiagParamScopeInObject:
  5000. return _u("DiagParamScopeInObject");
  5001. default:
  5002. AssertMsg(false, "Missing a debug scope type.");
  5003. return _u("");
  5004. }
  5005. }
  5006. #endif
  5007. #if ENABLE_TTD
  5008. Js::PropertyId DebuggerScope::GetPropertyIdForSlotIndex_TTD(uint32 slotIndex) const
  5009. {
  5010. const Js::DebuggerScopeProperty& scopeProperty = this->scopeProperties->Item(slotIndex);
  5011. return scopeProperty.propId;
  5012. }
  5013. #endif
  5014. // Updates the current offset of where the property is first initialized. This is used to
  5015. // detect whether or not a property is in a dead zone when broken in the debugger.
  5016. // location - The slot array index or register slot location of where the property is stored.
  5017. // propertyId - The property ID of the property.
  5018. // byteCodeOffset - The offset to set the initialization point at.
  5019. // isFunctionDeclaration - Whether or not the property is a function declaration or not. Used for verification.
  5020. // <returns> - True if the property was found and updated for the current scope, else false.
  5021. bool DebuggerScope::UpdatePropertyInitializationOffset(
  5022. RegSlot location,
  5023. Js::PropertyId propertyId,
  5024. int byteCodeOffset,
  5025. bool isFunctionDeclaration /*= false*/)
  5026. {
  5027. if (UpdatePropertyInitializationOffsetInternal(location, propertyId, byteCodeOffset, isFunctionDeclaration))
  5028. {
  5029. return true;
  5030. }
  5031. if (siblingScope != nullptr && siblingScope->UpdatePropertyInitializationOffsetInternal(location, propertyId, byteCodeOffset, isFunctionDeclaration))
  5032. {
  5033. return true;
  5034. }
  5035. return false;
  5036. }
  5037. bool DebuggerScope::UpdatePropertyInitializationOffsetInternal(
  5038. RegSlot location,
  5039. Js::PropertyId propertyId,
  5040. int byteCodeOffset,
  5041. bool isFunctionDeclaration /*= false*/)
  5042. {
  5043. if (scopeProperties == nullptr)
  5044. {
  5045. return false;
  5046. }
  5047. for (int i = 0; i < scopeProperties->Count(); ++i)
  5048. {
  5049. DebuggerScopeProperty propertyItem = scopeProperties->Item(i);
  5050. if (propertyItem.propId == propertyId && propertyItem.location == location)
  5051. {
  5052. if (propertyItem.byteCodeInitializationOffset == Constants::InvalidByteCodeOffset)
  5053. {
  5054. propertyItem.byteCodeInitializationOffset = byteCodeOffset;
  5055. scopeProperties->SetExistingItem(i, propertyItem);
  5056. }
  5057. #if DBG
  5058. else
  5059. {
  5060. // If the bytecode initialization offset is not Constants::InvalidByteCodeOffset,
  5061. // it means we have two or more functions declared in the same scope with the same name
  5062. // and one has already been marked. We track each location with a property entry
  5063. // on the debugging side (when calling DebuggerScope::AddProperty()) as opposed to scanning
  5064. // and checking if the property already exists each time we add in order to avoid duplicates.
  5065. AssertMsg(isFunctionDeclaration, "Only function declarations can be defined more than once in the same scope with the same name.");
  5066. AssertMsg(propertyItem.byteCodeInitializationOffset == byteCodeOffset, "The bytecode offset for all function declarations should be identical for this scope.");
  5067. }
  5068. #endif // DBG
  5069. return true;
  5070. }
  5071. }
  5072. return false;
  5073. }
  5074. // Updates the debugger scopes fields due to a regeneration of bytecode (happens during debugger attach or detach, for
  5075. // example).
  5076. void DebuggerScope::UpdateDueToByteCodeRegeneration(DiagExtraScopesType scopeType, int start, RegSlot scopeLocation)
  5077. {
  5078. #if DBG
  5079. if (this->scopeType != Js::DiagUnknownScope)
  5080. {
  5081. // If the scope is unknown, it was deserialized without a scope type. Otherwise, it should not have changed.
  5082. // The scope type can change on a re-parse in certain scenarios related to eval detection in legacy mode -> Winblue: 272122
  5083. AssertMsg(this->scopeType == scopeType, "The debugger scope type should not have changed when generating bytecode again.");
  5084. }
  5085. #endif // DBG
  5086. this->scopeType = scopeType;
  5087. this->SetBegin(start);
  5088. if(this->scopeProperties)
  5089. {
  5090. this->scopeProperties->Clear();
  5091. }
  5092. // Reset the scope location as it may have changed during bytecode generation from the last run.
  5093. this->SetScopeLocation(scopeLocation);
  5094. if (siblingScope)
  5095. {
  5096. // If we had a sibling scope during initial parsing, clear it now so that it will be reset
  5097. // when it is retrieved during this bytecode generation pass, in GetSiblingScope().
  5098. // GetSiblingScope() will ensure that the FunctionBody currentDebuggerScopeIndex value is
  5099. // updated accordingly to account for future scopes coming after the sibling.
  5100. // Calling of GetSiblingScope() will happen when register properties are added to this scope
  5101. // via TrackRegisterPropertyForDebugger().
  5102. siblingScope = nullptr;
  5103. }
  5104. }
  5105. void DebuggerScope::UpdatePropertiesInForInOrOfCollectionScope()
  5106. {
  5107. if (this->scopeProperties != nullptr)
  5108. {
  5109. this->scopeProperties->All([&](Js::DebuggerScopeProperty& propertyItem)
  5110. {
  5111. propertyItem.flags |= DebuggerScopePropertyFlags_ForInOrOfCollection;
  5112. return true;
  5113. });
  5114. }
  5115. }
  5116. void DebuggerScope::EnsurePropertyListIsAllocated()
  5117. {
  5118. if (this->scopeProperties == nullptr)
  5119. {
  5120. this->scopeProperties = RecyclerNew(this->recycler, DebuggerScopePropertyList, this->recycler);
  5121. }
  5122. }
  5123. // Checks if the passed in ByteCodeGenerator offset is in this scope's being/end range.
  5124. bool DebuggerScope::IsOffsetInScope(int offset) const
  5125. {
  5126. Assert(this->range.end != -1);
  5127. return this->range.Includes(offset);
  5128. }
  5129. // Determines if the DebuggerScope contains a property with the passed in ID and
  5130. // location in the internal property list.
  5131. // propertyId - The ID of the property to search for.
  5132. // location - The slot array index or register to search for.
  5133. // outScopeProperty - Optional parameter that will return the property, if found.
  5134. bool DebuggerScope::Contains(Js::PropertyId propertyId, RegSlot location) const
  5135. {
  5136. DebuggerScopeProperty tempProperty;
  5137. return TryGetProperty(propertyId, location, &tempProperty);
  5138. }
  5139. // Gets whether or not the scope is a block scope (non-catch or with).
  5140. bool DebuggerScope::IsBlockScope() const
  5141. {
  5142. AssertMsg(this->scopeType != Js::DiagBlockScopeRangeEnd, "Debugger scope type should never be set to range end - only reserved for marking the end of a scope (not persisted).");
  5143. return this->scopeType == Js::DiagBlockScopeDirect
  5144. || this->scopeType == Js::DiagBlockScopeInObject
  5145. || this->scopeType == Js::DiagBlockScopeInSlot
  5146. || this->scopeType == Js::DiagBlockScopeRangeEnd;
  5147. }
  5148. // Gets whether or not the scope is a catch block scope.
  5149. bool DebuggerScope::IsCatchScope() const
  5150. {
  5151. return this->scopeType == Js::DiagCatchScopeDirect
  5152. || this->scopeType == Js::DiagCatchScopeInObject
  5153. || this->scopeType == Js::DiagCatchScopeInSlot;
  5154. }
  5155. // Gets whether or not the scope is a with block scope.
  5156. bool DebuggerScope::IsWithScope() const
  5157. {
  5158. return this->scopeType == Js::DiagWithScope;
  5159. }
  5160. // Gets whether or not the scope is a slot array scope.
  5161. bool DebuggerScope::IsSlotScope() const
  5162. {
  5163. return this->scopeType == Js::DiagBlockScopeInSlot
  5164. || this->scopeType == Js::DiagCatchScopeInSlot;
  5165. }
  5166. bool DebuggerScope::IsParamScope() const
  5167. {
  5168. return this->scopeType == Js::DiagParamScope
  5169. || this->scopeType == Js::DiagParamScopeInObject;
  5170. }
  5171. // Gets whether or not the scope has any properties in it.
  5172. bool DebuggerScope::HasProperties() const
  5173. {
  5174. return this->scopeProperties && this->scopeProperties->Count() > 0;
  5175. }
  5176. // Checks if this scope is an ancestor of the passed in scope.
  5177. bool DebuggerScope::IsAncestorOf(const DebuggerScope* potentialChildScope)
  5178. {
  5179. if (potentialChildScope == nullptr)
  5180. {
  5181. // If the child scope is null, it represents the global scope which
  5182. // cannot be a child of anything.
  5183. return false;
  5184. }
  5185. const DebuggerScope* currentScope = potentialChildScope;
  5186. while (currentScope)
  5187. {
  5188. if (currentScope->GetParentScope() == this)
  5189. {
  5190. return true;
  5191. }
  5192. currentScope = currentScope->GetParentScope();
  5193. }
  5194. return false;
  5195. }
  5196. // Checks if all properties of the scope are currently in a dead zone given the specified offset.
  5197. bool DebuggerScope::AreAllPropertiesInDeadZone(int byteCodeOffset) const
  5198. {
  5199. if (!this->HasProperties())
  5200. {
  5201. return false;
  5202. }
  5203. return this->scopeProperties->All([&](Js::DebuggerScopeProperty& propertyItem)
  5204. {
  5205. return propertyItem.IsInDeadZone(byteCodeOffset);
  5206. });
  5207. }
  5208. // Attempts to get the specified property. Returns true if the property was copied to the structure; false otherwise.
  5209. bool DebuggerScope::TryGetProperty(Js::PropertyId propertyId, RegSlot location, DebuggerScopeProperty* outScopeProperty) const
  5210. {
  5211. Assert(outScopeProperty);
  5212. if (scopeProperties == nullptr)
  5213. {
  5214. return false;
  5215. }
  5216. for (int i = 0; i < scopeProperties->Count(); ++i)
  5217. {
  5218. DebuggerScopeProperty propertyItem = scopeProperties->Item(i);
  5219. if (propertyItem.propId == propertyId && propertyItem.location == location)
  5220. {
  5221. *outScopeProperty = propertyItem;
  5222. return true;
  5223. }
  5224. }
  5225. return false;
  5226. }
  5227. bool DebuggerScope::TryGetValidProperty(Js::PropertyId propertyId, RegSlot location, int offset, DebuggerScopeProperty* outScopeProperty, bool* isInDeadZone) const
  5228. {
  5229. if (TryGetProperty(propertyId, location, outScopeProperty))
  5230. {
  5231. if (IsOffsetInScope(offset))
  5232. {
  5233. if (isInDeadZone != nullptr)
  5234. {
  5235. *isInDeadZone = outScopeProperty->IsInDeadZone(offset);
  5236. }
  5237. return true;
  5238. }
  5239. }
  5240. return false;
  5241. }
  5242. void DebuggerScope::SetBegin(int begin)
  5243. {
  5244. range.begin = begin;
  5245. if (siblingScope != nullptr)
  5246. {
  5247. siblingScope->SetBegin(begin);
  5248. }
  5249. }
  5250. void DebuggerScope::SetEnd(int end)
  5251. {
  5252. range.end = end;
  5253. if (siblingScope != nullptr)
  5254. {
  5255. siblingScope->SetEnd(end);
  5256. }
  5257. }
  5258. // Finds the common ancestor scope between this scope and the passed in scope.
  5259. // Returns nullptr if the scopes are part of different trees.
  5260. DebuggerScope* DebuggerScope::FindCommonAncestor(DebuggerScope* debuggerScope)
  5261. {
  5262. AnalysisAssert(debuggerScope);
  5263. if (this == debuggerScope)
  5264. {
  5265. return debuggerScope;
  5266. }
  5267. if (this->IsAncestorOf(debuggerScope))
  5268. {
  5269. return this;
  5270. }
  5271. if (debuggerScope->IsAncestorOf(this))
  5272. {
  5273. return debuggerScope;
  5274. }
  5275. DebuggerScope* firstNode = this;
  5276. DebuggerScope* secondNode = debuggerScope;
  5277. int firstDepth = firstNode->GetScopeDepth();
  5278. int secondDepth = secondNode->GetScopeDepth();
  5279. // Calculate the depth difference in order to bring the deep node up to the sibling
  5280. // level of the shorter node.
  5281. int depthDifference = abs(firstDepth - secondDepth);
  5282. DebuggerScope*& nodeToBringUp = firstDepth > secondDepth ? firstNode : secondNode;
  5283. while (depthDifference > 0)
  5284. {
  5285. AnalysisAssert(nodeToBringUp);
  5286. nodeToBringUp = nodeToBringUp->GetParentScope();
  5287. --depthDifference;
  5288. }
  5289. // Move up the tree and see where the nodes meet.
  5290. while (firstNode && secondNode)
  5291. {
  5292. if (firstNode == secondNode)
  5293. {
  5294. return firstNode;
  5295. }
  5296. firstNode = firstNode->GetParentScope();
  5297. secondNode = secondNode->GetParentScope();
  5298. }
  5299. // The nodes are not part of the same scope tree.
  5300. return nullptr;
  5301. }
  5302. // Gets the depth of the scope in the parent link tree.
  5303. int DebuggerScope::GetScopeDepth() const
  5304. {
  5305. int depth = 0;
  5306. const DebuggerScope* currentDebuggerScope = this;
  5307. while (currentDebuggerScope)
  5308. {
  5309. currentDebuggerScope = currentDebuggerScope->GetParentScope();
  5310. ++depth;
  5311. }
  5312. return depth;
  5313. }
  5314. bool ScopeObjectChain::TryGetDebuggerScopePropertyInfo(PropertyId propertyId, RegSlot location, int offset, bool* isPropertyInDebuggerScope, bool *isConst, bool* isInDeadZone)
  5315. {
  5316. Assert(pScopeChain);
  5317. Assert(isPropertyInDebuggerScope);
  5318. Assert(isConst);
  5319. *isPropertyInDebuggerScope = false;
  5320. *isConst = false;
  5321. // Search through each block scope until we find the current scope. If the register was found
  5322. // in any of the scopes going down until we reach the scope of the debug break, then it's in scope.
  5323. // if found but not in the scope, the out param will be updated (since it is actually a let or const), so that caller can make a call accordingly.
  5324. for (int i = 0; i < pScopeChain->Count(); i++)
  5325. {
  5326. Js::DebuggerScope *debuggerScope = pScopeChain->Item(i);
  5327. DebuggerScopeProperty debuggerScopeProperty;
  5328. if (!debuggerScope->IsParamScope() && debuggerScope->TryGetProperty(propertyId, location, &debuggerScopeProperty))
  5329. {
  5330. bool isOffsetInScope = debuggerScope->IsOffsetInScope(offset);
  5331. // For the Object scope, all the properties will have the same location (-1) so they can match. Use further check below to determine the propertyInDebuggerScope
  5332. *isPropertyInDebuggerScope = isOffsetInScope || !debuggerScope->IsBlockObjectScope();
  5333. if (isOffsetInScope)
  5334. {
  5335. if (isInDeadZone != nullptr)
  5336. {
  5337. *isInDeadZone = debuggerScopeProperty.IsInDeadZone(offset);
  5338. }
  5339. *isConst = debuggerScopeProperty.IsConst();
  5340. return true;
  5341. }
  5342. }
  5343. }
  5344. return false;
  5345. }
  5346. void FunctionBody::AllocateForInCache()
  5347. {
  5348. uint profiledForInLoopCount = this->GetProfiledForInLoopCount();
  5349. if (profiledForInLoopCount == 0)
  5350. {
  5351. return;
  5352. }
  5353. this->SetAuxPtr<AuxPointerType::ForInCacheArray>(AllocatorNewArrayZ(CacheAllocator, this->GetScriptContext()->GetEnumeratorAllocator(), EnumeratorCache, profiledForInLoopCount));
  5354. }
  5355. EnumeratorCache * FunctionBody::GetForInCache(uint index)
  5356. {
  5357. Assert(index < this->GetProfiledForInLoopCount());
  5358. return &this->GetAuxPtr<AuxPointerType::ForInCacheArray>()[index];
  5359. }
  5360. EnumeratorCache * FunctionBody::GetForInCacheArray()
  5361. {
  5362. return this->GetAuxPtrWithLock<AuxPointerType::ForInCacheArray>();
  5363. }
  5364. void FunctionBody::CleanUpForInCache(bool isShutdown)
  5365. {
  5366. uint profiledForInLoopCount = this->GetProfiledForInLoopCount();
  5367. if (profiledForInLoopCount == 0)
  5368. {
  5369. return;
  5370. }
  5371. EnumeratorCache * forInCacheArray = this->GetAuxPtr<AuxPointerType::ForInCacheArray>();
  5372. if (forInCacheArray)
  5373. {
  5374. if (isShutdown)
  5375. {
  5376. memset(forInCacheArray, 0, sizeof(EnumeratorCache) * profiledForInLoopCount);
  5377. }
  5378. else
  5379. {
  5380. AllocatorDeleteArray(CacheAllocator, this->GetScriptContext()->GetEnumeratorAllocator(), profiledForInLoopCount, forInCacheArray);
  5381. this->SetAuxPtr<AuxPointerType::ForInCacheArray>(nullptr);
  5382. }
  5383. }
  5384. }
  5385. void FunctionBody::AllocateInlineCache()
  5386. {
  5387. Assert(this->inlineCaches == nullptr);
  5388. uint isInstInlineCacheStart = this->GetInlineCacheCount();
  5389. uint totalCacheCount = isInstInlineCacheStart + GetIsInstInlineCacheCount();
  5390. if (totalCacheCount != 0)
  5391. {
  5392. // Root object inline cache are not leaf
  5393. void ** inlineCaches = RecyclerNewArrayZ(this->m_scriptContext->GetRecycler(),
  5394. void*, totalCacheCount);
  5395. #if DBG
  5396. this->m_inlineCacheTypes = RecyclerNewArrayLeafZ(this->m_scriptContext->GetRecycler(),
  5397. byte, totalCacheCount);
  5398. #endif
  5399. uint i = 0;
  5400. uint plainInlineCacheEnd = GetRootObjectLoadInlineCacheStart();
  5401. __analysis_assume(plainInlineCacheEnd <= totalCacheCount);
  5402. for (; i < plainInlineCacheEnd; i++)
  5403. {
  5404. inlineCaches[i] = AllocatorNewZ(InlineCacheAllocator,
  5405. this->m_scriptContext->GetInlineCacheAllocator(), InlineCache);
  5406. }
  5407. Js::RootObjectBase * rootObject = this->GetRootObject();
  5408. ThreadContext * threadContext = this->GetScriptContext()->GetThreadContext();
  5409. uint rootObjectLoadInlineCacheEnd = GetRootObjectLoadMethodInlineCacheStart();
  5410. __analysis_assume(rootObjectLoadInlineCacheEnd <= totalCacheCount);
  5411. for (; i < rootObjectLoadInlineCacheEnd; i++)
  5412. {
  5413. inlineCaches[i] = rootObject->GetInlineCache(
  5414. threadContext->GetPropertyName(this->GetPropertyIdFromCacheId(i)), false, false);
  5415. }
  5416. uint rootObjectLoadMethodInlineCacheEnd = GetRootObjectStoreInlineCacheStart();
  5417. __analysis_assume(rootObjectLoadMethodInlineCacheEnd <= totalCacheCount);
  5418. for (; i < rootObjectLoadMethodInlineCacheEnd; i++)
  5419. {
  5420. inlineCaches[i] = rootObject->GetInlineCache(
  5421. threadContext->GetPropertyName(this->GetPropertyIdFromCacheId(i)), true, false);
  5422. }
  5423. uint rootObjectStoreInlineCacheEnd = isInstInlineCacheStart;
  5424. __analysis_assume(rootObjectStoreInlineCacheEnd <= totalCacheCount);
  5425. for (; i < rootObjectStoreInlineCacheEnd; i++)
  5426. {
  5427. #pragma prefast(suppress:6386, "The analysis assume didn't help prefast figure out this is in range")
  5428. inlineCaches[i] = rootObject->GetInlineCache(
  5429. threadContext->GetPropertyName(this->GetPropertyIdFromCacheId(i)), false, true);
  5430. }
  5431. for (; i < totalCacheCount; i++)
  5432. {
  5433. inlineCaches[i] = AllocatorNewStructZ(CacheAllocator,
  5434. this->m_scriptContext->GetIsInstInlineCacheAllocator(), IsInstInlineCache);
  5435. }
  5436. #if DBG
  5437. this->m_inlineCacheTypes = RecyclerNewArrayLeafZ(this->m_scriptContext->GetRecycler(),
  5438. byte, totalCacheCount);
  5439. #endif
  5440. this->inlineCaches = inlineCaches;
  5441. }
  5442. }
  5443. InlineCache *FunctionBody::GetInlineCache(uint index)
  5444. {
  5445. Assert(this->inlineCaches != nullptr);
  5446. Assert(index < this->GetInlineCacheCount());
  5447. #if DBG
  5448. Assert(this->m_inlineCacheTypes[index] == InlineCacheTypeNone ||
  5449. this->m_inlineCacheTypes[index] == InlineCacheTypeInlineCache);
  5450. this->m_inlineCacheTypes[index] = InlineCacheTypeInlineCache;
  5451. #endif
  5452. return reinterpret_cast<InlineCache *>(this->inlineCaches[index]);
  5453. }
  5454. bool FunctionBody::CanFunctionObjectHaveInlineCaches()
  5455. {
  5456. if (this->DoStackNestedFunc() || this->IsCoroutine())
  5457. {
  5458. return false;
  5459. }
  5460. uint totalCacheCount = this->GetInlineCacheCount() + this->GetIsInstInlineCacheCount();
  5461. if (PHASE_FORCE(Js::ScriptFunctionWithInlineCachePhase, this) && totalCacheCount > 0)
  5462. {
  5463. return true;
  5464. }
  5465. // Only have inline caches on function object for possible inlining candidates.
  5466. // Since we don't know the size of the top function, check against the maximum possible inline threshold
  5467. // Negative inline byte code size threshold will disable inline cache on function object.
  5468. const int byteCodeSizeThreshold = CONFIG_FLAG(InlineThreshold) + CONFIG_FLAG(InlineThresholdAdjustCountInSmallFunction);
  5469. if (byteCodeSizeThreshold < 0 || this->GetByteCodeWithoutLDACount() > (uint)byteCodeSizeThreshold)
  5470. {
  5471. return false;
  5472. }
  5473. // Negative FuncObjectInlineCacheThreshold will disable inline cache on function object.
  5474. if (CONFIG_FLAG(FuncObjectInlineCacheThreshold) < 0 || totalCacheCount > (uint)CONFIG_FLAG(FuncObjectInlineCacheThreshold) || totalCacheCount == 0)
  5475. {
  5476. return false;
  5477. }
  5478. return true;
  5479. }
  5480. void** FunctionBody::GetInlineCaches()
  5481. {
  5482. return this->inlineCaches;
  5483. }
  5484. #if DBG
  5485. byte* FunctionBody::GetInlineCacheTypes()
  5486. {
  5487. return this->m_inlineCacheTypes;
  5488. }
  5489. #endif
  5490. IsInstInlineCache *FunctionBody::GetIsInstInlineCache(uint index)
  5491. {
  5492. Assert(this->inlineCaches != nullptr);
  5493. Assert(index < GetIsInstInlineCacheCount());
  5494. index += this->GetInlineCacheCount();
  5495. #if DBG
  5496. Assert(this->m_inlineCacheTypes[index] == InlineCacheTypeNone ||
  5497. this->m_inlineCacheTypes[index] == InlineCacheTypeIsInst);
  5498. this->m_inlineCacheTypes[index] = InlineCacheTypeIsInst;
  5499. #endif
  5500. return reinterpret_cast<IsInstInlineCache *>(this->inlineCaches[index]);
  5501. }
  5502. PolymorphicInlineCache * FunctionBody::GetPolymorphicInlineCache(uint index)
  5503. {
  5504. return this->polymorphicInlineCaches.GetInlineCache(this, index);
  5505. }
  5506. PolymorphicInlineCache * FunctionBody::CreateNewPolymorphicInlineCache(uint index, PropertyId propertyId, InlineCache * inlineCache)
  5507. {
  5508. Assert(GetPolymorphicInlineCache(index) == nullptr);
  5509. // Only create polymorphic inline caches for non-root inline cache indexes
  5510. if (index < GetRootObjectLoadInlineCacheStart()
  5511. #if DBG
  5512. && !PHASE_OFF1(Js::PolymorphicInlineCachePhase)
  5513. #endif
  5514. )
  5515. {
  5516. PolymorphicInlineCache * polymorphicInlineCache = CreatePolymorphicInlineCache(index, MinPolymorphicInlineCacheSize);
  5517. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  5518. if (PHASE_VERBOSE_TRACE1(Js::PolymorphicInlineCachePhase))
  5519. {
  5520. this->DumpFullFunctionName();
  5521. Output::Print(_u(": New PIC, index = %d, size = %d\n"), index, MinPolymorphicInlineCacheSize);
  5522. }
  5523. #endif
  5524. #if PHASE_PRINT_INTRUSIVE_TESTTRACE1
  5525. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5526. #endif
  5527. PHASE_PRINT_INTRUSIVE_TESTTRACE1(
  5528. Js::PolymorphicInlineCachePhase,
  5529. _u("TestTrace PIC: New, Function %s (%s), 0x%x, index = %d, size = %d\n"), this->GetDisplayName(), this->GetDebugNumberSet(debugStringBuffer), polymorphicInlineCache, index, MinPolymorphicInlineCacheSize);
  5530. uint indexInPolymorphicCache = polymorphicInlineCache->GetInlineCacheIndexForType(inlineCache->GetType());
  5531. inlineCache->CopyTo(propertyId, m_scriptContext, &(polymorphicInlineCache->GetInlineCaches()[indexInPolymorphicCache]));
  5532. polymorphicInlineCache->UpdateInlineCachesFillInfo(indexInPolymorphicCache, true /*set*/);
  5533. return polymorphicInlineCache;
  5534. }
  5535. return nullptr;
  5536. }
  5537. PolymorphicInlineCache * FunctionBody::CreateBiggerPolymorphicInlineCache(uint index, PropertyId propertyId)
  5538. {
  5539. PolymorphicInlineCache * polymorphicInlineCache = GetPolymorphicInlineCache(index);
  5540. Assert(polymorphicInlineCache && polymorphicInlineCache->CanAllocateBigger());
  5541. uint16 polymorphicInlineCacheSize = polymorphicInlineCache->GetSize();
  5542. uint16 newPolymorphicInlineCacheSize = PolymorphicInlineCache::GetNextSize(polymorphicInlineCacheSize);
  5543. Assert(newPolymorphicInlineCacheSize > polymorphicInlineCacheSize);
  5544. PolymorphicInlineCache * newPolymorphicInlineCache = CreatePolymorphicInlineCache(index, newPolymorphicInlineCacheSize);
  5545. polymorphicInlineCache->CopyTo(propertyId, m_scriptContext, newPolymorphicInlineCache);
  5546. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  5547. if (PHASE_VERBOSE_TRACE1(Js::PolymorphicInlineCachePhase))
  5548. {
  5549. this->DumpFullFunctionName();
  5550. Output::Print(_u(": Bigger PIC, index = %d, oldSize = %d, newSize = %d\n"), index, polymorphicInlineCacheSize, newPolymorphicInlineCacheSize);
  5551. }
  5552. #endif
  5553. #if PHASE_PRINT_INTRUSIVE_TESTTRACE1
  5554. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5555. #endif
  5556. PHASE_PRINT_INTRUSIVE_TESTTRACE1(
  5557. Js::PolymorphicInlineCachePhase,
  5558. _u("TestTrace PIC: Bigger, Function %s (%s), 0x%x, index = %d, size = %d\n"), this->GetDisplayName(), this->GetDebugNumberSet(debugStringBuffer), newPolymorphicInlineCache, index, newPolymorphicInlineCacheSize);
  5559. return newPolymorphicInlineCache;
  5560. }
  5561. void FunctionBody::ResetInlineCaches()
  5562. {
  5563. SetInlineCacheCount(0);
  5564. SetRootObjectLoadInlineCacheStart(0);
  5565. SetRootObjectStoreInlineCacheStart(0);
  5566. SetIsInstInlineCacheCount(0);
  5567. this->inlineCaches = nullptr;
  5568. this->polymorphicInlineCaches.Reset();
  5569. }
  5570. PolymorphicInlineCache * FunctionBody::CreatePolymorphicInlineCache(uint index, uint16 size)
  5571. {
  5572. Recycler * recycler = this->m_scriptContext->GetRecycler();
  5573. PolymorphicInlineCache * newPolymorphicInlineCache = FunctionBodyPolymorphicInlineCache::New(size, this);
  5574. this->polymorphicInlineCaches.SetInlineCache(recycler, this, index, newPolymorphicInlineCache);
  5575. return newPolymorphicInlineCache;
  5576. }
  5577. uint FunctionBody::NewObjectLiteral()
  5578. {
  5579. Assert(this->GetObjectLiteralTypes() == nullptr);
  5580. return IncObjLiteralCount();
  5581. }
  5582. Field(DynamicType*)* FunctionBody::GetObjectLiteralTypeRef(uint index)
  5583. {
  5584. Assert(index < GetObjLiteralCount());
  5585. auto literalTypes = this->GetObjectLiteralTypes();
  5586. Assert(literalTypes != nullptr);
  5587. return literalTypes + index;
  5588. }
  5589. Field(DynamicType*)* FunctionBody::GetObjectLiteralTypeRefWithLock(uint index)
  5590. {
  5591. Assert(index < GetObjLiteralCount());
  5592. auto literalTypes = this->GetObjectLiteralTypesWithLock();
  5593. Assert(literalTypes != nullptr);
  5594. return literalTypes + index;
  5595. }
  5596. void FunctionBody::AllocateObjectLiteralTypeArray()
  5597. {
  5598. Assert(this->GetObjectLiteralTypes() == nullptr);
  5599. uint objLiteralCount = GetObjLiteralCount();
  5600. if (objLiteralCount == 0)
  5601. {
  5602. return;
  5603. }
  5604. this->SetObjectLiteralTypes(RecyclerNewArrayZ(this->GetScriptContext()->GetRecycler(), DynamicType *, objLiteralCount));
  5605. }
  5606. uint FunctionBody::NewLiteralRegex()
  5607. {
  5608. if (this->GetLiteralRegexes() != nullptr)
  5609. {
  5610. // This is a function nested in a redeferred function, so we won't regenerate byte code and won't make use of the index.
  5611. // The regex count is already correct, so don't increment it.
  5612. return 0;
  5613. }
  5614. return IncLiteralRegexCount();
  5615. }
  5616. void FunctionBody::AllocateLiteralRegexArray()
  5617. {
  5618. Assert(!this->GetLiteralRegexes());
  5619. uint32 literalRegexCount = GetLiteralRegexCount();
  5620. if (literalRegexCount == 0)
  5621. {
  5622. return;
  5623. }
  5624. this->SetLiteralRegexs(RecyclerNewArrayZ(m_scriptContext->GetRecycler(), UnifiedRegex::RegexPattern *, literalRegexCount));
  5625. }
  5626. #ifdef ASMJS_PLAT
  5627. AsmJsFunctionInfo* FunctionBody::AllocateAsmJsFunctionInfo()
  5628. {
  5629. Assert( !this->GetAsmJsFunctionInfo() );
  5630. this->SetAuxPtr<AuxPointerType::AsmJsFunctionInfo>(RecyclerNew( m_scriptContext->GetRecycler(), AsmJsFunctionInfo));
  5631. return this->GetAsmJsFunctionInfo();
  5632. }
  5633. AsmJsModuleInfo* FunctionBody::AllocateAsmJsModuleInfo()
  5634. {
  5635. Assert( !this->GetAsmJsModuleInfo() );
  5636. Recycler* rec = m_scriptContext->GetRecycler();
  5637. this->SetAuxPtr<AuxPointerType::AsmJsModuleInfo>(RecyclerNew(rec, AsmJsModuleInfo, rec));
  5638. return this->GetAsmJsModuleInfo();
  5639. }
  5640. #endif
  5641. PropertyIdArray * FunctionBody::AllocatePropertyIdArrayForFormals(uint32 size, uint32 count, byte extraSlots)
  5642. {
  5643. //TODO: saravind: Should the allocation be a Leaf Allocation?
  5644. PropertyIdArray * formalsPropIdArray = RecyclerNewPlus(GetScriptContext()->GetRecycler(), size, Js::PropertyIdArray, count, extraSlots);
  5645. SetFormalsPropIdArray(formalsPropIdArray);
  5646. return formalsPropIdArray;
  5647. }
  5648. UnifiedRegex::RegexPattern *FunctionBody::GetLiteralRegex(const uint index)
  5649. {
  5650. Assert(index < GetLiteralRegexCount());
  5651. Assert(this->GetLiteralRegexes());
  5652. return this->GetLiteralRegexes()[index];
  5653. }
  5654. UnifiedRegex::RegexPattern *FunctionBody::GetLiteralRegexWithLock(const uint index)
  5655. {
  5656. Assert(index < GetLiteralRegexCount());
  5657. Assert(this->GetLiteralRegexesWithLock());
  5658. return this->GetLiteralRegexesWithLock()[index];
  5659. }
  5660. void FunctionBody::SetLiteralRegex(const uint index, UnifiedRegex::RegexPattern *const pattern)
  5661. {
  5662. Assert(index < GetLiteralRegexCount());
  5663. Assert(this->GetLiteralRegexes());
  5664. auto literalRegexes = this->GetLiteralRegexes();
  5665. if (literalRegexes[index] && literalRegexes[index] == pattern)
  5666. {
  5667. return;
  5668. }
  5669. Assert(!literalRegexes[index]);
  5670. literalRegexes[index] = pattern;
  5671. }
  5672. void FunctionBody::ResetObjectLiteralTypes()
  5673. {
  5674. this->SetObjectLiteralTypes(nullptr);
  5675. this->SetObjLiteralCount(0);
  5676. }
  5677. void FunctionBody::ResetLiteralRegexes()
  5678. {
  5679. SetLiteralRegexCount(0);
  5680. this->SetLiteralRegexs(nullptr);
  5681. }
  5682. Js::AuxArray<uint32> * FunctionBody::AllocateSlotIdInCachedScopeToNestedIndexArray(uint32 slotCount)
  5683. {
  5684. Js::AuxArray<uint32> * slotIdToNestedIndexArray = RecyclerNewPlusLeaf(GetScriptContext()->GetRecycler(), slotCount * sizeof(uint32), Js::AuxArray<uint32>, slotCount);
  5685. SetSlotIdInCachedScopeToNestedIndexArray(slotIdToNestedIndexArray);
  5686. return slotIdToNestedIndexArray;
  5687. }
  5688. #if ENABLE_NATIVE_CODEGEN
  5689. ProfileId* FunctionBody::CreateCallSiteToCallApplyCallSiteArray()
  5690. {
  5691. Assert(this->GetCallSiteToCallApplyCallSiteArray() == nullptr);
  5692. uint count = this->GetProfiledCallSiteCount();
  5693. if (count != 0)
  5694. {
  5695. this->SetCallSiteToCallApplyCallSiteArray(RecyclerNewArrayLeaf(this->m_scriptContext->GetRecycler(), ProfileId, count));
  5696. for (uint i = 0; i < count; i++)
  5697. {
  5698. this->GetCallSiteToCallApplyCallSiteArray()[i] = Js::Constants::NoProfileId;
  5699. }
  5700. }
  5701. return this->GetCallSiteToCallApplyCallSiteArray();
  5702. }
  5703. #endif
  5704. void FunctionBody::ResetProfileIds()
  5705. {
  5706. #if ENABLE_PROFILE_INFO
  5707. Assert(!HasDynamicProfileInfo()); // profile data relies on the profile ID counts; it should not have been created yet
  5708. Assert(!this->GetCodeGenRuntimeData()); // relies on 'profiledCallSiteCount'
  5709. profiledCallSiteCount = 0;
  5710. profiledArrayCallSiteCount = 0;
  5711. profiledReturnTypeCount = 0;
  5712. profiledSlotCount = 0;
  5713. profiledLdLenCount = 0;
  5714. profiledLdElemCount = 0;
  5715. profiledStElemCount = 0;
  5716. #endif
  5717. }
  5718. void FunctionBody::ResetByteCodeGenState()
  5719. {
  5720. // Byte code generation failed for this function. Revert any intermediate state being tracked in the function body, in
  5721. // case byte code generation is attempted again for this function body.
  5722. DebugOnly(this->UnlockCounters());
  5723. ResetInlineCaches();
  5724. ResetObjectLiteralTypes();
  5725. ResetLiteralRegexes();
  5726. ResetLoops();
  5727. ResetProfileIds();
  5728. ResetSlotIdInCachedScopeToNestedIndexArray();
  5729. SetFirstTmpRegister(Constants::NoRegister);
  5730. SetLocalClosureRegister(Constants::NoRegister);
  5731. SetParamClosureRegister(Constants::NoRegister);
  5732. SetLocalFrameDisplayRegister(Constants::NoRegister);
  5733. SetEnvRegister(Constants::NoRegister);
  5734. SetThisRegisterForEventHandler(Constants::NoRegister);
  5735. SetFirstInnerScopeRegister(Constants::NoRegister);
  5736. SetFuncExprScopeRegister(Constants::NoRegister);
  5737. SetInnerScopeCount(0);
  5738. hasCachedScopePropIds = false;
  5739. this->SetConstantCount(0);
  5740. this->SetConstTable(nullptr);
  5741. AssertMsg(!this->byteCodeBlock || !this->IsWasmFunction(), "We should never reset the bytecode block for Wasm");
  5742. this->byteCodeBlock = nullptr;
  5743. // Also, remove the function body from the source info to prevent any further processing
  5744. // of the function such as attempts to set breakpoints.
  5745. if (GetIsFuncRegistered())
  5746. {
  5747. this->GetUtf8SourceInfo()->RemoveFunctionBody(this);
  5748. }
  5749. // There is other state that is set by the byte code generator but the state should be the same each time byte code
  5750. // generation is done for the function, so it doesn't need to be reverted
  5751. }
  5752. void FunctionBody::ResetByteCodeGenVisitState()
  5753. {
  5754. // This function body is about to be visited by the byte code generator after defer-parsing it. Since the previous visit
  5755. // pass may have failed, we need to restore state that is tracked on the function body by the visit pass.
  5756. // Note: do not reset literal regexes if the function has already been compiled (e.g., is a parsed function enclosed by a
  5757. // redeferred function) as we will not use the count of literals anyway, and the counters may be accessed by the background thread.
  5758. DebugOnly(this->UnlockCounters());
  5759. if (this->byteCodeBlock == nullptr)
  5760. {
  5761. ResetLiteralRegexes();
  5762. }
  5763. }
  5764. #if ENABLE_NATIVE_CODEGEN
  5765. const FunctionCodeGenRuntimeData *FunctionBody::GetInlineeCodeGenRuntimeData(const ProfileId profiledCallSiteId) const
  5766. {
  5767. Assert(profiledCallSiteId < profiledCallSiteCount);
  5768. auto codeGenRuntimeData = this->GetCodeGenRuntimeDataWithLock();
  5769. return codeGenRuntimeData ? codeGenRuntimeData[profiledCallSiteId] : nullptr;
  5770. }
  5771. const FunctionCodeGenRuntimeData *FunctionBody::GetInlineeCodeGenRuntimeDataForTargetInlinee(const ProfileId profiledCallSiteId, Js::FunctionBody *inlineeFuncBody) const
  5772. {
  5773. Assert(profiledCallSiteId < profiledCallSiteCount);
  5774. auto codeGenRuntimeData = this->GetCodeGenRuntimeDataWithLock();
  5775. if (!codeGenRuntimeData)
  5776. {
  5777. return nullptr;
  5778. }
  5779. const FunctionCodeGenRuntimeData *runtimeData = codeGenRuntimeData[profiledCallSiteId];
  5780. while (runtimeData && runtimeData->GetFunctionBody() != inlineeFuncBody)
  5781. {
  5782. runtimeData = runtimeData->GetNext();
  5783. }
  5784. return runtimeData;
  5785. }
  5786. template<Js::FunctionProxy::AuxPointerType auxType>
  5787. FunctionCodeGenRuntimeData * FunctionBody::EnsureCodeGenRuntimeDataCommon(
  5788. Recycler *const recycler,
  5789. __in_range(0, profiledCallSiteCount - 1) const ProfileId profiledCallSiteId,
  5790. FunctionBody *const inlinee)
  5791. {
  5792. Assert(recycler);
  5793. Assert(profiledCallSiteId < profiledCallSiteCount);
  5794. Assert(inlinee);
  5795. if (this->GetAuxPtr(auxType) == nullptr)
  5796. {
  5797. FunctionCodeGenRuntimeData ** codeGenRuntimeData = RecyclerNewArrayZ(recycler, FunctionCodeGenRuntimeData *, profiledCallSiteCount);
  5798. this->SetAuxPtr(auxType, codeGenRuntimeData);
  5799. }
  5800. Field(FunctionCodeGenRuntimeData *)* codeGenRuntimeData = this->GetAuxPtr<auxType>();
  5801. Field(FunctionCodeGenRuntimeData *) const inlineeData = codeGenRuntimeData[profiledCallSiteId];
  5802. if (inlineeData == nullptr)
  5803. {
  5804. FunctionCodeGenRuntimeData * runtimeData = RecyclerNew(recycler, FunctionCodeGenRuntimeData, inlinee);
  5805. codeGenRuntimeData[profiledCallSiteId] = runtimeData;
  5806. return runtimeData;
  5807. }
  5808. // Find the right code gen runtime data
  5809. FunctionCodeGenRuntimeData * next = inlineeData;
  5810. while (next && (next->GetFunctionBody() != inlinee))
  5811. {
  5812. next = next->GetNext();
  5813. }
  5814. if (next)
  5815. {
  5816. return next;
  5817. }
  5818. FunctionCodeGenRuntimeData * runtimeData = RecyclerNew(recycler, FunctionCodeGenRuntimeData, inlinee);
  5819. runtimeData->SetupRuntimeDataChain(inlineeData);
  5820. codeGenRuntimeData[profiledCallSiteId] = runtimeData;
  5821. return runtimeData;
  5822. }
  5823. FunctionCodeGenRuntimeData *FunctionBody::EnsureInlineeCodeGenRuntimeData(
  5824. Recycler *const recycler,
  5825. __in_range(0, profiledCallSiteCount - 1) const ProfileId profiledCallSiteId,
  5826. FunctionBody *const inlinee)
  5827. {
  5828. return EnsureCodeGenRuntimeDataCommon<AuxPointerType::CodeGenRuntimeData>(recycler, profiledCallSiteId, inlinee);
  5829. }
  5830. FunctionCodeGenRuntimeData * FunctionBody::EnsureCallbackInlineeCodeGenRuntimeData(
  5831. Recycler *const recycler,
  5832. __in_range(0, profiledCallSiteCount - 1) const ProfileId profiledCallSiteId,
  5833. FunctionBody *const inlinee)
  5834. {
  5835. return EnsureCodeGenRuntimeDataCommon<AuxPointerType::CodeGenCallbackRuntimeData>(recycler, profiledCallSiteId, inlinee);
  5836. }
  5837. const FunctionCodeGenRuntimeData * FunctionBody::GetCallApplyTargetInlineeCodeGenRuntimeData(const ProfileId callApplyCallSiteId) const
  5838. {
  5839. Assert(callApplyCallSiteId < GetProfiledCallApplyCallSiteCount());
  5840. Field(FunctionCodeGenRuntimeData*)* codeGenRuntimeData = this->GetCodeGenCallApplyTargetRuntimeDataWithLock();
  5841. return codeGenRuntimeData ? codeGenRuntimeData[callApplyCallSiteId] : nullptr;
  5842. }
  5843. FunctionCodeGenRuntimeData * FunctionBody::EnsureCallApplyTargetInlineeCodeGenRuntimeData(
  5844. Recycler *const recycler,
  5845. const ProfileId callApplyCallSiteId,
  5846. FunctionBody *const inlinee)
  5847. {
  5848. Assert(callApplyCallSiteId < this->GetProfiledCallApplyCallSiteCount());
  5849. return EnsureCodeGenRuntimeDataCommon<AuxPointerType::CodeGenCallApplyTargetRuntimeData>(recycler, callApplyCallSiteId, inlinee);
  5850. }
  5851. const FunctionCodeGenRuntimeData *FunctionBody::GetLdFldInlineeCodeGenRuntimeData(const InlineCacheIndex inlineCacheIndex) const
  5852. {
  5853. Assert(inlineCacheIndex < this->GetInlineCacheCount());
  5854. auto data = this->GetCodeGenGetSetRuntimeDataWithLock();
  5855. return (data != nullptr) ? data[inlineCacheIndex] : nullptr;
  5856. }
  5857. FunctionCodeGenRuntimeData *FunctionBody::EnsureLdFldInlineeCodeGenRuntimeData(
  5858. Recycler *const recycler,
  5859. const InlineCacheIndex inlineCacheIndex,
  5860. FunctionBody *const inlinee)
  5861. {
  5862. Assert(recycler);
  5863. Assert(inlineCacheIndex < this->GetInlineCacheCount());
  5864. Assert(inlinee);
  5865. if (this->GetCodeGenGetSetRuntimeData() == nullptr)
  5866. {
  5867. const auto codeGenRuntimeData = RecyclerNewArrayZ(recycler, FunctionCodeGenRuntimeData *, this->GetInlineCacheCount());
  5868. this->SetCodeGenGetSetRuntimeData(codeGenRuntimeData);
  5869. }
  5870. auto codeGenGetSetRuntimeData = this->GetCodeGenGetSetRuntimeData();
  5871. const auto inlineeData = codeGenGetSetRuntimeData[inlineCacheIndex];
  5872. if (inlineeData)
  5873. {
  5874. return inlineeData;
  5875. }
  5876. return codeGenGetSetRuntimeData[inlineCacheIndex] = RecyclerNew(recycler, FunctionCodeGenRuntimeData, inlinee);
  5877. }
  5878. const FunctionCodeGenRuntimeData * FunctionBody::GetCallbackInlineeCodeGenRuntimeData(const ProfileId profiledCallSiteId) const
  5879. {
  5880. Assert(profiledCallSiteId < profiledCallSiteCount);
  5881. Field(FunctionCodeGenRuntimeData*)* codeGenRuntimeData = this->GetCodeGenCallbackRuntimeDataWithLock();
  5882. return codeGenRuntimeData ? codeGenRuntimeData[profiledCallSiteId] : nullptr;
  5883. }
  5884. #endif
  5885. void FunctionBody::AllocateLoopHeaders()
  5886. {
  5887. Assert(this->GetLoopHeaderArray() == nullptr);
  5888. uint loopCount = GetLoopCount();
  5889. if (loopCount != 0)
  5890. {
  5891. this->SetLoopHeaderArray(RecyclerNewArrayZ(this->m_scriptContext->GetRecycler(), LoopHeader, loopCount));
  5892. auto loopHeaderArray = this->GetLoopHeaderArray();
  5893. for (uint i = 0; i < loopCount; i++)
  5894. {
  5895. loopHeaderArray[i].Init(this);
  5896. }
  5897. }
  5898. }
  5899. void FunctionBody::ReleaseLoopHeaders()
  5900. {
  5901. #if ENABLE_NATIVE_CODEGEN
  5902. this->MapLoopHeaders([](uint loopNumber, LoopHeader * loopHeader)
  5903. {
  5904. loopHeader->ReleaseEntryPoints();
  5905. });
  5906. #endif
  5907. }
  5908. void FunctionBody::ResetLoops()
  5909. {
  5910. SetLoopCount(0);
  5911. this->SetLoopHeaderArray(nullptr);
  5912. }
  5913. void FunctionBody::RestoreOldDefaultEntryPoint(FunctionEntryPointInfo* oldEntryPointInfo,
  5914. JavascriptMethod oldOriginalEntryPoint,
  5915. FunctionEntryPointInfo* newEntryPointInfo)
  5916. {
  5917. Assert(newEntryPointInfo);
  5918. this->SetDefaultFunctionEntryPointInfo(oldEntryPointInfo, oldOriginalEntryPoint);
  5919. this->entryPoints->RemoveAt(newEntryPointInfo->entryPointIndex);
  5920. }
  5921. FunctionEntryPointInfo* FunctionBody::CreateNewDefaultEntryPoint()
  5922. {
  5923. Recycler *const recycler = this->m_scriptContext->GetRecycler();
  5924. const JavascriptMethod currentThunk = m_scriptContext->CurrentThunk;
  5925. FunctionEntryPointInfo *const entryPointInfo =
  5926. RecyclerNewFinalized(
  5927. recycler,
  5928. FunctionEntryPointInfo,
  5929. this,
  5930. currentThunk,
  5931. m_scriptContext->GetThreadContext());
  5932. AddEntryPointToEntryPointList(entryPointInfo);
  5933. {
  5934. // Allocations in this region may trigger expiry and cause unexpected changes to state
  5935. AUTO_NO_EXCEPTION_REGION;
  5936. Js::JavascriptMethod originalEntryPoint, directEntryPoint;
  5937. #if ENABLE_NATIVE_CODEGEN
  5938. FunctionEntryPointInfo *const simpleJitEntryPointInfo = GetSimpleJitEntryPointInfo();
  5939. if(simpleJitEntryPointInfo && GetExecutionMode() == ExecutionMode::FullJit)
  5940. {
  5941. directEntryPoint =
  5942. originalEntryPoint = simpleJitEntryPointInfo->GetNativeEntrypoint();
  5943. }
  5944. else
  5945. #endif
  5946. {
  5947. #if DYNAMIC_INTERPRETER_THUNK
  5948. // If the dynamic interpreter thunk hasn't been created yet, then the entry point can be set to
  5949. // the default entry point. Otherwise, since the new default entry point is being created to
  5950. // move back to the interpreter, the original entry point is going to be the dynamic interpreter thunk
  5951. originalEntryPoint =
  5952. m_dynamicInterpreterThunk
  5953. ? reinterpret_cast<JavascriptMethod>(InterpreterThunkEmitter::ConvertToEntryPoint(m_dynamicInterpreterThunk))
  5954. : DefaultEntryThunk;
  5955. #else
  5956. originalEntryPoint = DefaultEntryThunk;
  5957. #endif
  5958. directEntryPoint = currentThunk == DefaultEntryThunk ? originalEntryPoint : currentThunk;
  5959. }
  5960. entryPointInfo->jsMethod = directEntryPoint;
  5961. SetDefaultFunctionEntryPointInfo(entryPointInfo, originalEntryPoint);
  5962. }
  5963. return entryPointInfo;
  5964. }
  5965. LoopHeader *FunctionBody::GetLoopHeader(uint index) const
  5966. {
  5967. Assert(this->GetLoopHeaderArray() != nullptr);
  5968. Assert(index < GetLoopCount());
  5969. return &this->GetLoopHeaderArray()[index];
  5970. }
  5971. LoopHeader *FunctionBody::GetLoopHeaderWithLock(uint index) const
  5972. {
  5973. Assert(this->GetLoopHeaderArrayWithLock() != nullptr);
  5974. Assert(index < GetLoopCount());
  5975. return &this->GetLoopHeaderArrayWithLock()[index];
  5976. }
  5977. FunctionEntryPointInfo *FunctionBody::GetSimpleJitEntryPointInfo() const
  5978. {
  5979. return this->GetAuxPtr<AuxPointerType::SimpleJitEntryPointInfo>();
  5980. }
  5981. void FunctionBody::SetSimpleJitEntryPointInfo(FunctionEntryPointInfo *const entryPointInfo)
  5982. {
  5983. this->SetAuxPtr<AuxPointerType::SimpleJitEntryPointInfo>(entryPointInfo);
  5984. }
  5985. uint32 FunctionBody::GetInterpretedCount() const
  5986. {
  5987. return executionState.GetInterpretedCount();
  5988. }
  5989. uint32 FunctionBody::IncreaseInterpretedCount()
  5990. {
  5991. return executionState.IncreaseInterpretedCount();
  5992. }
  5993. void FunctionBody::SetAsmJsExecutionMode()
  5994. {
  5995. executionState.SetAsmJsExecutionMode();
  5996. }
  5997. void FunctionBody::SetDefaultInterpreterExecutionMode()
  5998. {
  5999. executionState.SetDefaultInterpreterExecutionMode();
  6000. }
  6001. ExecutionMode FunctionBody::GetExecutionMode() const
  6002. {
  6003. return executionState.GetExecutionMode();
  6004. }
  6005. ExecutionMode FunctionBody::GetInterpreterExecutionMode(const bool isPostBailout)
  6006. {
  6007. return executionState.GetInterpreterExecutionMode(isPostBailout);
  6008. }
  6009. bool FunctionBody::IsInterpreterExecutionMode() const
  6010. {
  6011. return GetExecutionMode() <= ExecutionMode::ProfilingInterpreter;
  6012. }
  6013. bool FunctionBody::TryTransitionToNextExecutionMode()
  6014. {
  6015. return executionState.TryTransitionToNextExecutionMode();
  6016. }
  6017. void FunctionBody::TryTransitionToNextInterpreterExecutionMode()
  6018. {
  6019. executionState.TryTransitionToNextInterpreterExecutionMode();
  6020. }
  6021. void FunctionBody::SetIsSpeculativeJitCandidate()
  6022. {
  6023. executionState.SetIsSpeculativeJitCandidate();
  6024. }
  6025. bool FunctionBody::TryTransitionToJitExecutionMode()
  6026. {
  6027. return executionState.TryTransitionToJitExecutionMode();
  6028. }
  6029. void FunctionBody::TransitionToSimpleJitExecutionMode()
  6030. {
  6031. executionState.TransitionToSimpleJitExecutionMode();
  6032. }
  6033. void FunctionBody::TransitionToFullJitExecutionMode()
  6034. {
  6035. executionState.TransitionToFullJitExecutionMode();
  6036. }
  6037. void FunctionBody::ReinitializeExecutionModeAndLimits()
  6038. {
  6039. // Do not remove wasCalledFromLoop
  6040. wasCalledFromLoop = false;
  6041. executionState.ReinitializeExecutionModeAndLimits(this);
  6042. }
  6043. void FunctionBody::ResetSimpleJitLimitAndCallCount()
  6044. {
  6045. Assert(GetDefaultFunctionEntryPointInfo() == GetSimpleJitEntryPointInfo());
  6046. executionState.ResetSimpleJitLimit();
  6047. ResetSimpleJitCallCount();
  6048. }
  6049. void FunctionBody::SetSimpleJitCallCount(const uint16 simpleJitLimit) const
  6050. {
  6051. Assert(GetExecutionMode() == ExecutionMode::SimpleJit);
  6052. Assert(GetDefaultFunctionEntryPointInfo() == GetSimpleJitEntryPointInfo());
  6053. // Simple JIT counts down and transitions on overflow
  6054. const uint8 limit = static_cast<uint8>(min(0xffui16, simpleJitLimit));
  6055. GetSimpleJitEntryPointInfo()->callsCount = limit == 0 ? 0 : limit - 1;
  6056. }
  6057. void FunctionBody::ResetSimpleJitCallCount()
  6058. {
  6059. uint32 interpretedCount = GetInterpretedCount();
  6060. uint16 simpleJitLimit = static_cast<uint16>(executionState.GetSimpleJitLimit());
  6061. SetSimpleJitCallCount(
  6062. simpleJitLimit > interpretedCount
  6063. ? simpleJitLimit - static_cast<uint16>(interpretedCount)
  6064. : 0ui16);
  6065. }
  6066. uint16 FunctionBody::GetProfiledIterations() const
  6067. {
  6068. return executionState.GetProfiledIterations();
  6069. }
  6070. void FunctionBody::OnFullJitDequeued(const FunctionEntryPointInfo *const entryPointInfo)
  6071. {
  6072. executionState.AssertIsInitialized();
  6073. Assert(GetExecutionMode() == ExecutionMode::FullJit);
  6074. Assert(entryPointInfo);
  6075. if(entryPointInfo != GetDefaultFunctionEntryPointInfo())
  6076. {
  6077. return;
  6078. }
  6079. // Re-queue the full JIT work item after this many iterations
  6080. executionState.SetFullJitRequeueThreshold(static_cast<uint16>(DEFAULT_CONFIG_FullJitRequeueThreshold));
  6081. }
  6082. void FunctionBody::TraceExecutionMode(const char *const eventDescription) const
  6083. {
  6084. executionState.AssertIsInitialized();
  6085. if(PHASE_TRACE(Phase::ExecutionModePhase, this))
  6086. {
  6087. DoTraceExecutionMode(eventDescription);
  6088. }
  6089. }
  6090. void FunctionBody::TraceInterpreterExecutionMode() const
  6091. {
  6092. executionState.AssertIsInitialized();
  6093. if(!PHASE_TRACE(Phase::ExecutionModePhase, this))
  6094. {
  6095. return;
  6096. }
  6097. switch(GetExecutionMode())
  6098. {
  6099. case ExecutionMode::Interpreter:
  6100. case ExecutionMode::AutoProfilingInterpreter:
  6101. case ExecutionMode::ProfilingInterpreter:
  6102. DoTraceExecutionMode(nullptr);
  6103. break;
  6104. }
  6105. }
  6106. void FunctionBody::DoTraceExecutionMode(const char *const eventDescription) const
  6107. {
  6108. Assert(PHASE_TRACE(Phase::ExecutionModePhase, this));
  6109. executionState.AssertIsInitialized();
  6110. char16 functionIdString[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  6111. Output::Print(
  6112. _u("ExecutionMode - ")
  6113. _u("function: %s (%s), ")
  6114. _u("mode: %S, ")
  6115. _u("size: %u, "),
  6116. GetDisplayName(),
  6117. GetDebugNumberSet(functionIdString),
  6118. ExecutionModeName(executionState.GetExecutionMode()),
  6119. GetByteCodeCount());
  6120. executionState.PrintLimits();
  6121. if(eventDescription)
  6122. {
  6123. Output::Print(_u(", event: %S"), eventDescription);
  6124. }
  6125. Output::Print(_u("\n"));
  6126. Output::Flush();
  6127. }
  6128. bool FunctionBody::DoSimpleJit() const
  6129. {
  6130. return
  6131. !PHASE_OFF(Js::SimpleJitPhase, this) &&
  6132. #ifdef ASMJS_PLAT
  6133. !GetIsAsmjsMode() &&
  6134. #endif
  6135. !GetScriptContext()->GetConfig()->IsNoNative() &&
  6136. !GetScriptContext()->IsScriptContextInDebugMode() &&
  6137. DoInterpreterProfile() &&
  6138. #pragma warning(suppress: 6235) // (<non-zero constant> || <expression>) is always a non-zero constant.
  6139. (!CONFIG_FLAG(NewSimpleJit) || DoInterpreterAutoProfile()) &&
  6140. !IsCoroutine(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt
  6141. }
  6142. bool FunctionBody::DoSimpleJitWithLock() const
  6143. {
  6144. return
  6145. !PHASE_OFF(Js::SimpleJitPhase, this) &&
  6146. #ifdef ASMJS_PLAT
  6147. !GetIsAsmjsMode() &&
  6148. #endif
  6149. !GetScriptContext()->GetConfig()->IsNoNative() &&
  6150. !this->IsInDebugMode() &&
  6151. DoInterpreterProfileWithLock() &&
  6152. #pragma warning(suppress: 6235) // (<non-zero constant> || <expression>) is always a non-zero constant.
  6153. (!CONFIG_FLAG(NewSimpleJit) || DoInterpreterAutoProfile()) &&
  6154. !IsCoroutine(); // Generator JIT requires bailout which SimpleJit cannot do since it skips GlobOpt
  6155. }
  6156. bool FunctionBody::DoSimpleJitDynamicProfile() const
  6157. {
  6158. Assert(DoSimpleJitWithLock());
  6159. return !PHASE_OFF(Js::SimpleJitDynamicProfilePhase, this) && !CONFIG_FLAG(NewSimpleJit);
  6160. }
  6161. bool FunctionBody::DoInterpreterProfile() const
  6162. {
  6163. #if ENABLE_PROFILE_INFO
  6164. return !PHASE_OFF(InterpreterProfilePhase, this) && DynamicProfileInfo::IsEnabled(this);
  6165. #else
  6166. return false;
  6167. #endif
  6168. }
  6169. bool FunctionBody::DoInterpreterProfileWithLock() const
  6170. {
  6171. #if ENABLE_PROFILE_INFO
  6172. return !PHASE_OFF(InterpreterProfilePhase, this) && DynamicProfileInfo::IsEnabled(this);
  6173. #else
  6174. return false;
  6175. #endif
  6176. }
  6177. bool FunctionBody::DoInterpreterAutoProfile() const
  6178. {
  6179. Assert(DoInterpreterProfile());
  6180. #ifdef ASMJS_PLAT
  6181. if (this->GetIsAsmjsMode()) return false;
  6182. #endif
  6183. return !PHASE_OFF(InterpreterAutoProfilePhase, this) && !this->IsInDebugMode();
  6184. }
  6185. bool FunctionBody::WasCalledFromLoop() const
  6186. {
  6187. return wasCalledFromLoop;
  6188. }
  6189. void FunctionBody::SetWasCalledFromLoop()
  6190. {
  6191. if(wasCalledFromLoop)
  6192. {
  6193. return;
  6194. }
  6195. wasCalledFromLoop = true;
  6196. if(Configuration::Global.flags.EnforceExecutionModeLimits)
  6197. {
  6198. if(PHASE_TRACE(Phase::ExecutionModePhase, this))
  6199. {
  6200. executionState.CommitExecutedIterations();
  6201. TraceExecutionMode("WasCalledFromLoop (before)");
  6202. }
  6203. }
  6204. else
  6205. {
  6206. // This function is likely going to be called frequently since it's called from a loop. Reduce the full JIT
  6207. // threshold to realize the full JIT perf benefit sooner.
  6208. executionState.CommitExecutedIterations();
  6209. TraceExecutionMode("WasCalledFromLoop (before)");
  6210. uint16 fullJitThreshold = executionState.GetFullJitThreshold();
  6211. if(fullJitThreshold > 1)
  6212. {
  6213. executionState.SetFullJitThreshold(fullJitThreshold / 2, !CONFIG_FLAG(NewSimpleJit));
  6214. }
  6215. }
  6216. {
  6217. // Reduce the loop interpreter limit too, for the same reasons as above
  6218. const uint oldLoopInterpreterLimit = GetLoopInterpreterLimit();
  6219. const uint newLoopInterpreterLimit = GetReducedLoopInterpretCount();
  6220. Assert(newLoopInterpreterLimit <= oldLoopInterpreterLimit);
  6221. SetLoopInterpreterLimit(newLoopInterpreterLimit);
  6222. // Adjust loop headers' interpret counts to ensure that loops will still be profiled a number of times before
  6223. // loop bodies are jitted
  6224. const uint oldLoopProfileThreshold = GetLoopProfileThreshold(oldLoopInterpreterLimit);
  6225. const uint newLoopProfileThreshold = GetLoopProfileThreshold(newLoopInterpreterLimit);
  6226. MapLoopHeaders([=](const uint index, LoopHeader *const loopHeader)
  6227. {
  6228. const uint interpretedCount = loopHeader->interpretCount;
  6229. if(interpretedCount <= newLoopProfileThreshold || interpretedCount >= oldLoopInterpreterLimit)
  6230. {
  6231. // The loop hasn't been profiled yet and wouldn't have started profiling even with the new profile
  6232. // threshold, or it has already been profiled the necessary minimum number of times based on the old limit
  6233. return;
  6234. }
  6235. if(interpretedCount <= oldLoopProfileThreshold)
  6236. {
  6237. // The loop hasn't been profiled yet, but would have started profiling with the new profile threshold. Start
  6238. // profiling on the next iteration.
  6239. loopHeader->interpretCount = newLoopProfileThreshold;
  6240. return;
  6241. }
  6242. // The loop has been profiled some already. Preserve the number of profiled iterations.
  6243. loopHeader->interpretCount = newLoopProfileThreshold + (interpretedCount - oldLoopProfileThreshold);
  6244. });
  6245. }
  6246. TraceExecutionMode("WasCalledFromLoop");
  6247. }
  6248. bool FunctionBody::RecentlyBailedOutOfJittedLoopBody() const
  6249. {
  6250. return recentlyBailedOutOfJittedLoopBody;
  6251. }
  6252. void FunctionBody::SetRecentlyBailedOutOfJittedLoopBody(const bool value)
  6253. {
  6254. recentlyBailedOutOfJittedLoopBody = value;
  6255. }
  6256. uint16 FunctionBody::GetMinProfileIterations()
  6257. {
  6258. return
  6259. static_cast<uint>(
  6260. CONFIG_FLAG(NewSimpleJit)
  6261. ? DEFAULT_CONFIG_MinProfileIterations
  6262. : DEFAULT_CONFIG_MinProfileIterations_OldSimpleJit);
  6263. }
  6264. uint16 FunctionBody::GetMinFunctionProfileIterations()
  6265. {
  6266. return GetMinProfileIterations();
  6267. }
  6268. uint FunctionBody::GetMinLoopProfileIterations(const uint loopInterpreterLimit)
  6269. {
  6270. return min(static_cast<uint>(GetMinProfileIterations()), loopInterpreterLimit);
  6271. }
  6272. uint FunctionBody::GetLoopProfileThreshold(const uint loopInterpreterLimit) const
  6273. {
  6274. return
  6275. DoInterpreterProfile()
  6276. ? DoInterpreterAutoProfile()
  6277. ? loopInterpreterLimit - GetMinLoopProfileIterations(loopInterpreterLimit)
  6278. : 0
  6279. : static_cast<uint>(-1);
  6280. }
  6281. uint FunctionBody::GetReducedLoopInterpretCount()
  6282. {
  6283. const uint loopInterpretCount = CONFIG_FLAG(LoopInterpretCount);
  6284. if(CONFIG_ISENABLED(LoopInterpretCountFlag))
  6285. {
  6286. return loopInterpretCount;
  6287. }
  6288. return max(loopInterpretCount / 3, GetMinLoopProfileIterations(loopInterpretCount));
  6289. }
  6290. uint FunctionBody::GetLoopInterpretCount(LoopHeader* loopHeader) const
  6291. {
  6292. if(loopHeader->isNested)
  6293. {
  6294. Assert(GetLoopInterpreterLimit() >= GetReducedLoopInterpretCount());
  6295. return GetReducedLoopInterpretCount();
  6296. }
  6297. return GetLoopInterpreterLimit();
  6298. }
  6299. bool FunctionBody::DoObjectHeaderInlining()
  6300. {
  6301. return !PHASE_OFF1(ObjectHeaderInliningPhase);
  6302. }
  6303. bool FunctionBody::DoObjectHeaderInliningForConstructors()
  6304. {
  6305. return !PHASE_OFF1(ObjectHeaderInliningForConstructorsPhase) && DoObjectHeaderInlining();
  6306. }
  6307. bool FunctionBody::DoObjectHeaderInliningForConstructor(const uint32 inlineSlotCapacity)
  6308. {
  6309. return inlineSlotCapacity == 0 ? DoObjectHeaderInliningForEmptyObjects() : DoObjectHeaderInliningForConstructors();
  6310. }
  6311. bool FunctionBody::DoObjectHeaderInliningForObjectLiterals()
  6312. {
  6313. return !PHASE_OFF1(ObjectHeaderInliningForObjectLiteralsPhase) && DoObjectHeaderInlining();
  6314. }
  6315. bool FunctionBody::DoObjectHeaderInliningForObjectLiteral(const uint32 inlineSlotCapacity)
  6316. {
  6317. return
  6318. inlineSlotCapacity == 0
  6319. ? DoObjectHeaderInliningForEmptyObjects()
  6320. : DoObjectHeaderInliningForObjectLiterals() &&
  6321. inlineSlotCapacity <= static_cast<uint32>(MaxPreInitializedObjectHeaderInlinedTypeInlineSlotCount);
  6322. }
  6323. bool FunctionBody::DoObjectHeaderInliningForObjectLiteral(
  6324. const PropertyIdArray *const propIds)
  6325. {
  6326. Assert(propIds);
  6327. return
  6328. DoObjectHeaderInliningForObjectLiteral(propIds->count) &&
  6329. PathTypeHandlerBase::UsePathTypeHandlerForObjectLiteral(propIds);
  6330. }
  6331. bool FunctionBody::DoObjectHeaderInliningForEmptyObjects()
  6332. {
  6333. #pragma prefast(suppress:6237, "(<zero> && <expression>) is always zero. <expression> is never evaluated and might have side effects.")
  6334. return PHASE_ON1(ObjectHeaderInliningForEmptyObjectsPhase) && DoObjectHeaderInlining();
  6335. }
  6336. void FunctionBody::Finalize(bool isShutdown)
  6337. {
  6338. #if ENABLE_DEBUG_CONFIG_OPTIONS
  6339. if (Js::Configuration::Global.flags.Instrument.IsEnabled(Js::LinearScanPhase, this->GetSourceContextId(), this->GetLocalFunctionId()))
  6340. {
  6341. this->DumpRegStats(this);
  6342. }
  6343. #endif
  6344. this->Cleanup(isShutdown);
  6345. this->CleanupSourceInfo(isShutdown);
  6346. this->CleanupFunctionProxyCounters();
  6347. }
  6348. void FunctionBody::OnMark()
  6349. {
  6350. this->m_hasActiveReference = true;
  6351. }
  6352. void FunctionBody::CleanupSourceInfo(bool isScriptContextClosing)
  6353. {
  6354. Assert(this->cleanedUp);
  6355. if (!sourceInfoCleanedUp)
  6356. {
  6357. if (GetIsFuncRegistered() && !isScriptContextClosing)
  6358. {
  6359. // If our function is registered, then there must
  6360. // be a Utf8SourceInfo pinned by it.
  6361. Assert(this->m_utf8SourceInfo);
  6362. this->GetUtf8SourceInfo()->RemoveFunctionBody(this);
  6363. }
  6364. if (this->m_sourceInfo.pSpanSequence != nullptr)
  6365. {
  6366. HeapDelete(this->m_sourceInfo.pSpanSequence);
  6367. this->m_sourceInfo.pSpanSequence = nullptr;
  6368. }
  6369. sourceInfoCleanedUp = true;
  6370. }
  6371. }
  6372. template<bool IsScriptContextShutdown>
  6373. void FunctionBody::CleanUpInlineCaches()
  6374. {
  6375. uint unregisteredInlineCacheCount = 0;
  6376. if (nullptr != this->inlineCaches)
  6377. {
  6378. // Inline caches are in this order
  6379. // plain inline cache
  6380. // root object load inline cache
  6381. // root object store inline cache
  6382. // isInst inline cache
  6383. // The inlineCacheCount includes all but isInst inline cache
  6384. uint i = 0;
  6385. uint plainInlineCacheEnd = GetRootObjectLoadInlineCacheStart();
  6386. for (; i < plainInlineCacheEnd; i++)
  6387. {
  6388. if (nullptr != this->inlineCaches[i])
  6389. {
  6390. InlineCache* inlineCache = (InlineCache*)this->inlineCaches[i];
  6391. if (IsScriptContextShutdown)
  6392. {
  6393. inlineCache->Clear();
  6394. }
  6395. else
  6396. {
  6397. if (inlineCache->RemoveFromInvalidationList())
  6398. {
  6399. unregisteredInlineCacheCount++;
  6400. }
  6401. AllocatorDelete(InlineCacheAllocator, this->m_scriptContext->GetInlineCacheAllocator(), inlineCache);
  6402. }
  6403. }
  6404. }
  6405. RootObjectBase * rootObjectBase = this->GetRootObject();
  6406. uint rootObjectLoadInlineCacheEnd = GetRootObjectLoadMethodInlineCacheStart();
  6407. for (; i < rootObjectLoadInlineCacheEnd; i++)
  6408. {
  6409. if (nullptr != this->inlineCaches[i])
  6410. {
  6411. if (IsScriptContextShutdown)
  6412. {
  6413. ((InlineCache*)this->inlineCaches[i])->Clear();
  6414. }
  6415. else
  6416. {
  6417. // A single root object inline caches for a given property is shared by all functions. It is ref counted
  6418. // and doesn't get released to the allocator until there are no more outstanding references. Thus we don't need
  6419. // to (and, in fact, cannot) remove it from the invalidation list here. Instead, we'll do it in ReleaseInlineCache
  6420. // when there are no more outstanding references.
  6421. unregisteredInlineCacheCount += rootObjectBase->ReleaseInlineCache(this->GetPropertyIdFromCacheId(i), false, false, IsScriptContextShutdown);
  6422. }
  6423. }
  6424. }
  6425. uint rootObjectLoadMethodInlineCacheEnd = GetRootObjectStoreInlineCacheStart();
  6426. for (; i < rootObjectLoadMethodInlineCacheEnd; i++)
  6427. {
  6428. if (nullptr != this->inlineCaches[i])
  6429. {
  6430. if (IsScriptContextShutdown)
  6431. {
  6432. ((InlineCache*)this->inlineCaches[i])->Clear();
  6433. }
  6434. else
  6435. {
  6436. // A single root object inline caches for a given property is shared by all functions. It is ref counted
  6437. // and doesn't get released to the allocator until there are no more outstanding references. Thus we don't need
  6438. // to (and, in fact, cannot) remove it from the invalidation list here. Instead, we'll do it in ReleaseInlineCache
  6439. // when there are no more outstanding references.
  6440. unregisteredInlineCacheCount += rootObjectBase->ReleaseInlineCache(this->GetPropertyIdFromCacheId(i), true, false, IsScriptContextShutdown);
  6441. }
  6442. }
  6443. }
  6444. uint rootObjectStoreInlineCacheEnd = this->GetInlineCacheCount();
  6445. for (; i < rootObjectStoreInlineCacheEnd; i++)
  6446. {
  6447. if (nullptr != this->inlineCaches[i])
  6448. {
  6449. if (IsScriptContextShutdown)
  6450. {
  6451. ((InlineCache*)this->inlineCaches[i])->Clear();
  6452. }
  6453. else
  6454. {
  6455. // A single root object inline caches for a given property is shared by all functions. It is ref counted
  6456. // and doesn't get released to the allocator until there are no more outstanding references. Thus we don't need
  6457. // to (and, in fact, cannot) remove it from the invalidation list here. Instead, we'll do it in ReleaseInlineCache
  6458. // when there are no more outstanding references.
  6459. unregisteredInlineCacheCount += rootObjectBase->ReleaseInlineCache(this->GetPropertyIdFromCacheId(i), false, true, IsScriptContextShutdown);
  6460. }
  6461. }
  6462. }
  6463. uint totalCacheCount = GetInlineCacheCount() + GetIsInstInlineCacheCount();
  6464. for (; i < totalCacheCount; i++)
  6465. {
  6466. if (nullptr != this->inlineCaches[i])
  6467. {
  6468. IsInstInlineCache* inlineCache = (IsInstInlineCache*)this->inlineCaches[i];
  6469. if (IsScriptContextShutdown)
  6470. {
  6471. inlineCache->Clear();
  6472. }
  6473. else
  6474. {
  6475. inlineCache->Unregister(this->m_scriptContext);
  6476. AllocatorDelete(CacheAllocator, this->m_scriptContext->GetIsInstInlineCacheAllocator(), inlineCache);
  6477. }
  6478. }
  6479. }
  6480. this->inlineCaches = nullptr;
  6481. }
  6482. auto codeGenRuntimeData = this->GetCodeGenRuntimeData();
  6483. if (nullptr != codeGenRuntimeData)
  6484. {
  6485. for (ProfileId i = 0; i < this->profiledCallSiteCount; i++)
  6486. {
  6487. const FunctionCodeGenRuntimeData* runtimeData = codeGenRuntimeData[i];
  6488. if (nullptr != runtimeData)
  6489. {
  6490. runtimeData->MapInlineCaches([&](InlineCache* inlineCache)
  6491. {
  6492. if (nullptr != inlineCache)
  6493. {
  6494. if (IsScriptContextShutdown)
  6495. {
  6496. inlineCache->Clear();
  6497. }
  6498. else
  6499. {
  6500. if (inlineCache->RemoveFromInvalidationList())
  6501. {
  6502. unregisteredInlineCacheCount++;
  6503. }
  6504. AllocatorDelete(InlineCacheAllocator, this->m_scriptContext->GetInlineCacheAllocator(), inlineCache);
  6505. }
  6506. }
  6507. });
  6508. }
  6509. }
  6510. }
  6511. auto codeGenGetSetRuntimeData = this->GetCodeGenGetSetRuntimeData();
  6512. if (codeGenGetSetRuntimeData != nullptr)
  6513. {
  6514. for (uint i = 0; i < this->GetInlineCacheCount(); i++)
  6515. {
  6516. auto runtimeData = codeGenGetSetRuntimeData[i];
  6517. if (nullptr != runtimeData)
  6518. {
  6519. runtimeData->MapInlineCaches([&](InlineCache* inlineCache)
  6520. {
  6521. if (nullptr != inlineCache)
  6522. {
  6523. if (IsScriptContextShutdown)
  6524. {
  6525. inlineCache->Clear();
  6526. }
  6527. else
  6528. {
  6529. if (inlineCache->RemoveFromInvalidationList())
  6530. {
  6531. unregisteredInlineCacheCount++;
  6532. }
  6533. AllocatorDelete(InlineCacheAllocator, this->m_scriptContext->GetInlineCacheAllocator(), inlineCache);
  6534. }
  6535. }
  6536. });
  6537. }
  6538. }
  6539. }
  6540. if (unregisteredInlineCacheCount > 0)
  6541. {
  6542. AssertMsg(!IsScriptContextShutdown, "Unregistration of inlineCache should only be done if this is not scriptContext shutdown.");
  6543. ThreadContext* threadContext = this->m_scriptContext->GetThreadContext();
  6544. threadContext->NotifyInlineCacheBatchUnregistered(unregisteredInlineCacheCount);
  6545. }
  6546. while (this->GetPolymorphicInlineCachesHead())
  6547. {
  6548. this->GetPolymorphicInlineCachesHead()->Finalize(IsScriptContextShutdown);
  6549. }
  6550. polymorphicInlineCaches.Reset();
  6551. }
  6552. void FunctionBody::CleanupRecyclerData(bool isShutdown, bool doEntryPointCleanupCaptureStack)
  6553. {
  6554. // If we're not shutting down (i.e closing the script context), we need to remove our inline caches from
  6555. // thread context's invalidation lists, and release memory back to the arena. During script context shutdown,
  6556. // we leave everything in place, because the inline cache arena will stay alive until script context is destroyed
  6557. // (i.e it's destructor has been called) and thus the invalidation lists are safe to keep references to caches from this
  6558. // script context. We will, however, zero all inline caches so that we don't have to process them on subsequent
  6559. // collections, which may still happen from other script contexts.
  6560. if (isShutdown)
  6561. {
  6562. CleanUpInlineCaches<true>();
  6563. }
  6564. else
  6565. {
  6566. CleanUpInlineCaches<false>();
  6567. }
  6568. if (this->entryPoints)
  6569. {
  6570. #if defined(ENABLE_DEBUG_CONFIG_OPTIONS) && !(DBG)
  6571. // On fretest builds, capture the stack only if the FreTestDiagMode switch is on
  6572. doEntryPointCleanupCaptureStack = doEntryPointCleanupCaptureStack && Js::Configuration::Global.flags.FreTestDiagMode;
  6573. #endif
  6574. this->MapEntryPoints([=](int index, FunctionEntryPointInfo* entryPoint)
  6575. {
  6576. if (nullptr != entryPoint)
  6577. {
  6578. // Finalize = Free up work item if it hasn't been released yet + entry point clean up
  6579. // isShutdown is false because cleanup is called only in the !isShutdown case
  6580. entryPoint->Finalize(isShutdown);
  6581. #if ENABLE_ENTRYPOINT_CLEANUP_TRACE
  6582. #if ENABLE_DEBUG_STACK_BACK_TRACE
  6583. // Do this separately since calling EntryPoint::Finalize doesn't capture the stack trace
  6584. // and in some calls to CleanupRecyclerData, we do want the stack trace captured.
  6585. if (doEntryPointCleanupCaptureStack)
  6586. {
  6587. entryPoint->CaptureCleanupStackTrace();
  6588. }
  6589. #endif
  6590. #endif
  6591. }
  6592. });
  6593. this->MapLoopHeaders([=](uint loopNumber, LoopHeader* header)
  6594. {
  6595. bool shuttingDown = isShutdown;
  6596. header->MapEntryPoints([=](int index, LoopEntryPointInfo* entryPoint)
  6597. {
  6598. entryPoint->Cleanup(shuttingDown, doEntryPointCleanupCaptureStack);
  6599. });
  6600. });
  6601. }
  6602. #ifdef PERF_COUNTERS
  6603. this->CleanupPerfCounter();
  6604. #endif
  6605. }
  6606. //
  6607. // Removes all references of the function body and causes clean up of entry points.
  6608. // If the cleanup has already occurred before this would be a no-op.
  6609. //
  6610. void FunctionBody::Cleanup(bool isScriptContextClosing)
  6611. {
  6612. if (cleanedUp)
  6613. {
  6614. return;
  6615. }
  6616. DebugOnly(this->SetIsClosing());
  6617. CleanupRecyclerData(isScriptContextClosing, false /* capture entry point cleanup stack trace */);
  6618. CleanUpForInCache(isScriptContextClosing);
  6619. this->SetObjLiteralCount(0);
  6620. this->SetScopeSlotArraySizes(0, 0);
  6621. // Manually clear these values to break any circular references
  6622. // that might prevent the script context from being disposed
  6623. this->auxPtrs = nullptr;
  6624. AssertMsg(isScriptContextClosing || !m_hasActiveReference || !this->byteCodeBlock || !this->IsWasmFunction(), "We should never reset the bytecode block for Wasm when still referenced");
  6625. this->byteCodeBlock = nullptr;
  6626. this->entryPoints = nullptr;
  6627. this->inlineCaches = nullptr;
  6628. this->cacheIdToPropertyIdMap = nullptr;
  6629. this->polymorphicInlineCaches.Reset();
  6630. this->SetConstTable(nullptr);
  6631. #if DYNAMIC_INTERPRETER_THUNK
  6632. if (this->HasInterpreterThunkGenerated())
  6633. {
  6634. JS_ETW(EtwTrace::LogMethodInterpreterThunkUnloadEvent(this));
  6635. if (!isScriptContextClosing)
  6636. {
  6637. if (m_isAsmJsFunction)
  6638. {
  6639. m_scriptContext->ReleaseDynamicAsmJsInterpreterThunk((BYTE*)this->m_dynamicInterpreterThunk, /*addtoFreeList*/ true);
  6640. }
  6641. else
  6642. {
  6643. m_scriptContext->ReleaseDynamicInterpreterThunk((BYTE*)this->m_dynamicInterpreterThunk, /*addtoFreeList*/ true);
  6644. }
  6645. }
  6646. }
  6647. #endif
  6648. this->cleanedUp = true;
  6649. }
  6650. #ifdef PERF_COUNTERS
  6651. void FunctionBody::CleanupPerfCounter()
  6652. {
  6653. // We might not have the byte code block yet if we defer parsed.
  6654. DWORD byteCodeSize = (this->byteCodeBlock? this->byteCodeBlock->GetLength() : 0)
  6655. + (this->GetAuxiliaryData() ? this->GetAuxiliaryData()->GetLength() : 0)
  6656. + (this->GetAuxiliaryContextData() ? this->GetAuxiliaryContextData()->GetLength() : 0);
  6657. PERF_COUNTER_SUB(Code, DynamicByteCodeSize, byteCodeSize);
  6658. if (this->m_isDeserializedFunction)
  6659. {
  6660. PERF_COUNTER_DEC(Code, DeserializedFunctionBody);
  6661. }
  6662. PERF_COUNTER_SUB(Code, TotalByteCodeSize, byteCodeSize);
  6663. }
  6664. #endif
  6665. void FunctionBody::CaptureDynamicProfileState(FunctionEntryPointInfo* entryPointInfo)
  6666. {
  6667. // DisableJIT-TODO: Move this to be under if DYNAMIC_PROFILE
  6668. #if ENABLE_NATIVE_CODEGEN
  6669. // (See also the FunctionBody member written in CaptureDynamicProfileState.)
  6670. this->SetSavedPolymorphicCacheState(entryPointInfo->GetNativeEntryPointData()->GetPendingPolymorphicCacheState());
  6671. this->savedInlinerVersion = entryPointInfo->GetNativeEntryPointData()->GetPendingInlinerVersion();
  6672. this->savedImplicitCallsFlags = entryPointInfo->GetNativeEntryPointData()->GetPendingImplicitCallFlags();
  6673. #endif
  6674. }
  6675. #if ENABLE_NATIVE_CODEGEN
  6676. BYTE FunctionBody::GetSavedInlinerVersion() const
  6677. {
  6678. Assert(this->dynamicProfileInfo != nullptr);
  6679. return this->savedInlinerVersion;
  6680. }
  6681. uint32 FunctionBody::GetSavedPolymorphicCacheState() const
  6682. {
  6683. Assert(this->dynamicProfileInfo != nullptr);
  6684. return this->savedPolymorphicCacheState;
  6685. }
  6686. void FunctionBody::SetSavedPolymorphicCacheState(uint32 state)
  6687. {
  6688. this->savedPolymorphicCacheState = state;
  6689. }
  6690. #endif
  6691. void FunctionBody::SetHasHotLoop()
  6692. {
  6693. if(hasHotLoop)
  6694. {
  6695. return;
  6696. }
  6697. hasHotLoop = true;
  6698. if(Configuration::Global.flags.EnforceExecutionModeLimits)
  6699. {
  6700. return;
  6701. }
  6702. executionState.CommitExecutedIterations();
  6703. TraceExecutionMode("HasHotLoop (before)");
  6704. if(executionState.GetFullJitThreshold() > 1)
  6705. {
  6706. executionState.SetFullJitThreshold(1, true);
  6707. }
  6708. TraceExecutionMode("HasHotLoop");
  6709. }
  6710. bool FunctionBody::IsInlineApplyDisabled()
  6711. {
  6712. return this->disableInlineApply;
  6713. }
  6714. void FunctionBody::SetDisableInlineApply(bool set)
  6715. {
  6716. this->disableInlineApply = set;
  6717. }
  6718. void FunctionBody::InitDisableInlineApply()
  6719. {
  6720. SetDisableInlineApply(
  6721. (this->GetLocalFunctionId() != Js::Constants::NoFunctionId && PHASE_OFF(Js::InlinePhase, this)) ||
  6722. PHASE_OFF(Js::InlineApplyPhase, this));
  6723. }
  6724. bool FunctionBody::CheckCalleeContextForInlining(FunctionProxy* calleeFunctionProxy)
  6725. {
  6726. return this->GetScriptContext() == calleeFunctionProxy->GetScriptContext() &&
  6727. this->GetSecondaryHostSourceContext() == calleeFunctionProxy->GetSecondaryHostSourceContext();
  6728. }
  6729. #if ENABLE_NATIVE_CODEGEN
  6730. ImplicitCallFlags FunctionBody::GetSavedImplicitCallsFlags() const
  6731. {
  6732. Assert(this->dynamicProfileInfo != nullptr);
  6733. return this->savedImplicitCallsFlags;
  6734. }
  6735. bool FunctionBody::HasNonBuiltInCallee()
  6736. {
  6737. for (ProfileId i = 0; i < profiledCallSiteCount; i++)
  6738. {
  6739. Assert(HasDynamicProfileInfo());
  6740. if (dynamicProfileInfo->MayHaveNonBuiltinCallee(i))
  6741. {
  6742. return true;
  6743. }
  6744. }
  6745. return false;
  6746. }
  6747. #endif
  6748. #ifdef ENABLE_SCRIPT_DEBUGGING
  6749. void FunctionBody::CheckAndRegisterFuncToDiag(ScriptContext *scriptContext)
  6750. {
  6751. // We will register function if, this is not host managed and it was not registered before.
  6752. if (GetHostSourceContext() == Js::Constants::NoHostSourceContext
  6753. && !m_isFuncRegisteredToDiag
  6754. && !scriptContext->GetDebugContext()->GetProbeContainer()->IsContextRegistered(GetSecondaryHostSourceContext()))
  6755. {
  6756. FunctionBody *pFunc = scriptContext->GetDebugContext()->GetProbeContainer()->GetGlobalFunc(scriptContext, GetSecondaryHostSourceContext());
  6757. if (pFunc)
  6758. {
  6759. // Existing behavior here is to ignore the OOM and since RegisterFuncToDiag
  6760. // can throw now, we simply ignore the OOM here
  6761. try
  6762. {
  6763. // Register the function to the PDM as eval code (the debugger app will show file as 'eval code')
  6764. pFunc->RegisterFuncToDiag(scriptContext, Constants::EvalCode);
  6765. }
  6766. catch (Js::OutOfMemoryException)
  6767. {
  6768. }
  6769. scriptContext->GetDebugContext()->GetProbeContainer()->RegisterContextToDiag(GetSecondaryHostSourceContext(), scriptContext->AllocatorForDiagnostics());
  6770. m_isFuncRegisteredToDiag = true;
  6771. }
  6772. }
  6773. else
  6774. {
  6775. m_isFuncRegisteredToDiag = true;
  6776. }
  6777. }
  6778. #endif
  6779. DebuggerScope* FunctionBody::RecordStartScopeObject(DiagExtraScopesType scopeType, int start, RegSlot scopeLocation, int* index)
  6780. {
  6781. Recycler* recycler = m_scriptContext->GetRecycler();
  6782. if (!GetScopeObjectChain())
  6783. {
  6784. SetScopeObjectChain(RecyclerNew(recycler, ScopeObjectChain, recycler));
  6785. }
  6786. // Check if we need to create the scope object or if it already exists from a previous bytecode
  6787. // generator pass.
  6788. DebuggerScope* debuggerScope = nullptr;
  6789. int currentDebuggerScopeIndex = this->GetNextDebuggerScopeIndex();
  6790. if (!this->TryGetDebuggerScopeAt(currentDebuggerScopeIndex, debuggerScope))
  6791. {
  6792. // Create a new debugger scope.
  6793. debuggerScope = AddScopeObject(scopeType, start, scopeLocation);
  6794. }
  6795. else
  6796. {
  6797. debuggerScope->UpdateDueToByteCodeRegeneration(scopeType, start, scopeLocation);
  6798. }
  6799. if(index)
  6800. {
  6801. *index = currentDebuggerScopeIndex;
  6802. }
  6803. return debuggerScope;
  6804. }
  6805. void FunctionBody::RecordEndScopeObject(DebuggerScope* currentScope, int end)
  6806. {
  6807. AssertMsg(currentScope, "No current debugger scope passed in.");
  6808. currentScope->SetEnd(end);
  6809. }
  6810. DebuggerScope * FunctionBody::AddScopeObject(DiagExtraScopesType scopeType, int start, RegSlot scopeLocation)
  6811. {
  6812. Assert(GetScopeObjectChain());
  6813. DebuggerScope *scopeObject = RecyclerNew(m_scriptContext->GetRecycler(), DebuggerScope, m_scriptContext->GetRecycler(), scopeType, scopeLocation, start);
  6814. GetScopeObjectChain()->pScopeChain->Add(scopeObject);
  6815. return scopeObject;
  6816. }
  6817. // Tries to retrieve the debugger scope at the specified index. If the index is out of range, nullptr
  6818. // is returned.
  6819. bool FunctionBody::TryGetDebuggerScopeAt(int index, DebuggerScope*& debuggerScope)
  6820. {
  6821. AssertMsg(this->GetScopeObjectChain(), "TryGetDebuggerScopeAt should only be called with a valid scope chain in place.");
  6822. Assert(index >= 0);
  6823. const Js::ScopeObjectChain::ScopeObjectChainList* scopeChain = this->GetScopeObjectChain()->pScopeChain;
  6824. if (index < scopeChain->Count())
  6825. {
  6826. debuggerScope = scopeChain->Item(index);
  6827. return true;
  6828. }
  6829. return false;
  6830. }
  6831. #if DYNAMIC_INTERPRETER_THUNK
  6832. DWORD FunctionBody::GetDynamicInterpreterThunkSize() const
  6833. {
  6834. return InterpreterThunkEmitter::ThunkSize;
  6835. }
  6836. #endif
  6837. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  6838. void
  6839. FunctionBody::DumpFullFunctionName()
  6840. {
  6841. char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  6842. Output::Print(_u("Function %s (%s)"), this->GetDisplayName(), this->GetDebugNumberSet(debugStringBuffer));
  6843. }
  6844. void FunctionBody::DumpFunctionId(bool pad)
  6845. {
  6846. uint sourceContextId = this->GetSourceContextInfo()->sourceContextId;
  6847. if (sourceContextId == Js::Constants::NoSourceContext)
  6848. {
  6849. if (this->IsDynamicScript())
  6850. {
  6851. Output::Print(pad? _u("Dy.%-3d") : _u("Dyn#%d"), this->GetLocalFunctionId());
  6852. }
  6853. else
  6854. {
  6855. // Function from LoadFile
  6856. Output::Print(pad? _u("%-5d") : _u("#%d"), this->GetLocalFunctionId());
  6857. }
  6858. }
  6859. else
  6860. {
  6861. Output::Print(pad? _u("%2d.%-3d") : _u("#%d.%d"), sourceContextId, this->GetLocalFunctionId());
  6862. }
  6863. }
  6864. #endif
  6865. void FunctionBody::EnsureAuxStatementData()
  6866. {
  6867. if (m_sourceInfo.m_auxStatementData == nullptr)
  6868. {
  6869. Recycler* recycler = m_scriptContext->GetRecycler();
  6870. // Note: allocating must be consistent with clean up in CleanupToReparse.
  6871. m_sourceInfo.m_auxStatementData = RecyclerNew(recycler, AuxStatementData);
  6872. }
  6873. }
  6874. /*static*/
  6875. void FunctionBody::GetShortNameFromUrl(__in LPCWSTR pchUrl, _Out_writes_z_(cchBuffer) LPWSTR pchShortName, __in size_t cchBuffer)
  6876. {
  6877. LPCWSTR pchFile = wcsrchr(pchUrl, _u('/'));
  6878. if (pchFile == nullptr)
  6879. {
  6880. pchFile = wcsrchr(pchUrl, _u('\\'));
  6881. }
  6882. LPCWSTR pchToCopy = pchUrl;
  6883. if (pchFile != nullptr)
  6884. {
  6885. pchToCopy = pchFile + 1;
  6886. }
  6887. wcscpy_s(pchShortName, cchBuffer, pchToCopy);
  6888. }
  6889. FunctionBody::StatementAdjustmentRecordList* FunctionBody::GetStatementAdjustmentRecords()
  6890. {
  6891. if (m_sourceInfo.m_auxStatementData)
  6892. {
  6893. return m_sourceInfo.m_auxStatementData->m_statementAdjustmentRecords;
  6894. }
  6895. return nullptr;
  6896. }
  6897. FunctionBody::CrossFrameEntryExitRecordList* FunctionBody::GetCrossFrameEntryExitRecords()
  6898. {
  6899. if (m_sourceInfo.m_auxStatementData)
  6900. {
  6901. return m_sourceInfo.m_auxStatementData->m_crossFrameBlockEntryExisRecords;
  6902. }
  6903. return nullptr;
  6904. }
  6905. void FunctionBody::RecordCrossFrameEntryExitRecord(uint byteCodeOffset, bool isEnterBlock)
  6906. {
  6907. this->EnsureAuxStatementData();
  6908. Recycler* recycler = this->m_scriptContext->GetRecycler();
  6909. if (this->GetCrossFrameEntryExitRecords() == nullptr)
  6910. {
  6911. m_sourceInfo.m_auxStatementData->m_crossFrameBlockEntryExisRecords = RecyclerNew(recycler, CrossFrameEntryExitRecordList, recycler);
  6912. }
  6913. Assert(this->GetCrossFrameEntryExitRecords());
  6914. CrossFrameEntryExitRecord record(byteCodeOffset, isEnterBlock);
  6915. this->GetCrossFrameEntryExitRecords()->Add(record); // Will copy stack value and put the copy into the container.
  6916. }
  6917. FunctionBody::AuxStatementData::AuxStatementData() : m_statementAdjustmentRecords(nullptr), m_crossFrameBlockEntryExisRecords(nullptr)
  6918. {
  6919. }
  6920. FunctionBody::StatementAdjustmentRecord::StatementAdjustmentRecord() :
  6921. m_byteCodeOffset((uint)Constants::InvalidOffset), m_adjustmentType(SAT_None)
  6922. {
  6923. }
  6924. FunctionBody::StatementAdjustmentRecord::StatementAdjustmentRecord(StatementAdjustmentType type, int byteCodeOffset) :
  6925. m_adjustmentType(type), m_byteCodeOffset(byteCodeOffset)
  6926. {
  6927. Assert(SAT_None <= type && type <= SAT_All);
  6928. }
  6929. FunctionBody::StatementAdjustmentRecord::StatementAdjustmentRecord(const StatementAdjustmentRecord& other) :
  6930. m_byteCodeOffset(other.m_byteCodeOffset), m_adjustmentType(other.m_adjustmentType)
  6931. {
  6932. }
  6933. uint FunctionBody::StatementAdjustmentRecord::GetByteCodeOffset()
  6934. {
  6935. Assert(m_byteCodeOffset != Constants::InvalidOffset);
  6936. return m_byteCodeOffset;
  6937. }
  6938. FunctionBody::StatementAdjustmentType FunctionBody::StatementAdjustmentRecord::GetAdjustmentType()
  6939. {
  6940. Assert(this->m_adjustmentType != SAT_None);
  6941. return m_adjustmentType;
  6942. }
  6943. FunctionBody::CrossFrameEntryExitRecord::CrossFrameEntryExitRecord() :
  6944. m_byteCodeOffset((uint)Constants::InvalidOffset), m_isEnterBlock(false)
  6945. {
  6946. }
  6947. FunctionBody::CrossFrameEntryExitRecord::CrossFrameEntryExitRecord(uint byteCodeOffset, bool isEnterBlock) :
  6948. m_byteCodeOffset(byteCodeOffset), m_isEnterBlock(isEnterBlock)
  6949. {
  6950. }
  6951. FunctionBody::CrossFrameEntryExitRecord::CrossFrameEntryExitRecord(const CrossFrameEntryExitRecord& other) :
  6952. m_byteCodeOffset(other.m_byteCodeOffset), m_isEnterBlock(other.m_isEnterBlock)
  6953. {
  6954. }
  6955. uint FunctionBody::CrossFrameEntryExitRecord::GetByteCodeOffset() const
  6956. {
  6957. Assert(m_byteCodeOffset != Constants::InvalidOffset);
  6958. return m_byteCodeOffset;
  6959. }
  6960. bool FunctionBody::CrossFrameEntryExitRecord::GetIsEnterBlock()
  6961. {
  6962. return m_isEnterBlock;
  6963. }
  6964. EntryPointPolymorphicInlineCacheInfo::EntryPointPolymorphicInlineCacheInfo(FunctionBody * functionBody) :
  6965. selfInfo(functionBody),
  6966. inlineeInfo(functionBody->GetRecycler())
  6967. {
  6968. }
  6969. PolymorphicInlineCacheInfo * EntryPointPolymorphicInlineCacheInfo::GetInlineeInfo(FunctionBody * inlineeFunctionBody)
  6970. {
  6971. SListCounted<PolymorphicInlineCacheInfo*, Recycler>::Iterator iter(&inlineeInfo);
  6972. while (iter.Next())
  6973. {
  6974. PolymorphicInlineCacheInfo * info = iter.Data();
  6975. if (info->GetFunctionBody() == inlineeFunctionBody)
  6976. {
  6977. return info;
  6978. }
  6979. }
  6980. return nullptr;
  6981. }
  6982. PolymorphicInlineCacheInfo * EntryPointPolymorphicInlineCacheInfo::EnsureInlineeInfo(Recycler * recycler, FunctionBody * inlineeFunctionBody)
  6983. {
  6984. PolymorphicInlineCacheInfo * info = GetInlineeInfo(inlineeFunctionBody);
  6985. if (!info)
  6986. {
  6987. info = RecyclerNew(recycler, PolymorphicInlineCacheInfo, inlineeFunctionBody);
  6988. inlineeInfo.Prepend(info);
  6989. }
  6990. return info;
  6991. }
  6992. void EntryPointPolymorphicInlineCacheInfo::SetPolymorphicInlineCache(FunctionBody * functionBody, uint index, PolymorphicInlineCache * polymorphicInlineCache, bool isInlinee, byte polyCacheUtil)
  6993. {
  6994. if (!isInlinee)
  6995. {
  6996. SetPolymorphicInlineCache(&selfInfo, functionBody, index, polymorphicInlineCache, polyCacheUtil);
  6997. Assert(functionBody == selfInfo.GetFunctionBody());
  6998. }
  6999. else
  7000. {
  7001. SetPolymorphicInlineCache(EnsureInlineeInfo(functionBody->GetScriptContext()->GetRecycler(), functionBody), functionBody, index, polymorphicInlineCache, polyCacheUtil);
  7002. Assert(functionBody == GetInlineeInfo(functionBody)->GetFunctionBody());
  7003. }
  7004. }
  7005. void EntryPointPolymorphicInlineCacheInfo::SetPolymorphicInlineCache(PolymorphicInlineCacheInfo * polymorphicInlineCacheInfo, FunctionBody * functionBody, uint index, PolymorphicInlineCache * polymorphicInlineCache, byte polyCacheUtil)
  7006. {
  7007. polymorphicInlineCacheInfo->GetPolymorphicInlineCaches()->SetInlineCache(functionBody->GetScriptContext()->GetRecycler(), functionBody, index, polymorphicInlineCache);
  7008. polymorphicInlineCacheInfo->GetUtilArray()->SetUtil(functionBody, index, polyCacheUtil);
  7009. }
  7010. void PolymorphicCacheUtilizationArray::SetUtil(Js::FunctionBody* functionBody, uint index, byte util)
  7011. {
  7012. Assert(functionBody);
  7013. Assert(index < functionBody->GetInlineCacheCount());
  7014. EnsureUtilArray(functionBody->GetScriptContext()->GetRecycler(), functionBody);
  7015. this->utilArray[index] = util;
  7016. }
  7017. byte PolymorphicCacheUtilizationArray::GetUtil(Js::FunctionBody* functionBody, uint index)
  7018. {
  7019. Assert(index < functionBody->GetInlineCacheCount());
  7020. return this->utilArray[index];
  7021. }
  7022. void PolymorphicCacheUtilizationArray::EnsureUtilArray(Recycler * const recycler, Js::FunctionBody * functionBody)
  7023. {
  7024. Assert(recycler);
  7025. Assert(functionBody);
  7026. Assert(functionBody->GetInlineCacheCount() != 0);
  7027. if(this->utilArray)
  7028. {
  7029. return;
  7030. }
  7031. this->utilArray = RecyclerNewArrayLeafZ(recycler, byte, functionBody->GetInlineCacheCount());
  7032. }
  7033. #if ENABLE_NATIVE_CODEGEN
  7034. DWORD_PTR EntryPointInfo::GetNativeAddress() const
  7035. {
  7036. // need the assert to skip for asmjsFunction as nativeAddress can be interpreter too for asmjs
  7037. Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone || this->isAsmJsFunction);
  7038. // !! this is illegal, however (by design) `IsInNativeAddressRange` needs it
  7039. return reinterpret_cast<DWORD_PTR>(this->GetNativeEntryPointData()->GetNativeAddress());
  7040. }
  7041. Js::JavascriptMethod EntryPointInfo::GetThunkAddress() const
  7042. {
  7043. Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone);
  7044. return this->GetNativeEntryPointData()->GetThunkAddress();
  7045. }
  7046. Js::JavascriptMethod EntryPointInfo::GetNativeEntrypoint() const
  7047. {
  7048. Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone || this->isAsmJsFunction);
  7049. Js::JavascriptMethod thunkAddress = this->GetNativeEntryPointData()->GetThunkAddress();
  7050. return thunkAddress ? thunkAddress : this->GetNativeEntryPointData()->GetNativeAddress();
  7051. }
  7052. ptrdiff_t EntryPointInfo::GetCodeSize() const
  7053. {
  7054. Assert(this->GetState() == CodeGenRecorded || this->GetState() == CodeGenDone);
  7055. return this->GetNativeEntryPointData()->GetCodeSize();
  7056. }
  7057. JitTransferData * EntryPointInfo::GetJitTransferData()
  7058. {
  7059. return this->GetNativeEntryPointData()->GetJitTransferData();
  7060. }
  7061. SmallSpanSequence* EntryPointInfo::GetNativeThrowSpanSequence() const
  7062. {
  7063. Assert(this->GetState() != NotScheduled);
  7064. Assert(this->GetState() != CleanedUp);
  7065. return this->GetNativeEntryPointData()->GetNativeThrowSpanSequence();
  7066. }
  7067. void EntryPointInfo::SetNativeThrowSpanSequence(SmallSpanSequence* seq)
  7068. {
  7069. Assert(this->GetState() == CodeGenQueued);
  7070. Assert(this->GetNativeEntryPointData()->GetNativeThrowSpanSequence() == nullptr);
  7071. this->GetNativeEntryPointData()->SetNativeThrowSpanSequence(seq);
  7072. }
  7073. uint EntryPointInfo::GetFrameHeight()
  7074. {
  7075. return this->GetNativeEntryPointData()->GetFrameHeight();
  7076. }
  7077. bool EntryPointInfo::HasInlinees()
  7078. {
  7079. return this->GetFrameHeight() > 0;
  7080. }
  7081. NativeEntryPointData * EntryPointInfo::EnsureNativeEntryPointData()
  7082. {
  7083. NativeEntryPointData * data = this->nativeEntryPointData;
  7084. if (data == nullptr)
  7085. {
  7086. #if ENABLE_OOP_NATIVE_CODEGEN
  7087. if (JITManager::GetJITManager()->IsOOPJITEnabled())
  7088. {
  7089. data = RecyclerNew(this->GetScriptContext()->GetRecycler(), OOPNativeEntryPointData);
  7090. }
  7091. else
  7092. #endif
  7093. {
  7094. data = RecyclerNew(this->GetScriptContext()->GetRecycler(), InProcNativeEntryPointData);
  7095. }
  7096. this->nativeEntryPointData = data;
  7097. }
  7098. return data;
  7099. }
  7100. bool EntryPointInfo::HasNativeEntryPointData() const
  7101. {
  7102. return this->nativeEntryPointData != nullptr;
  7103. }
  7104. NativeEntryPointData * EntryPointInfo::GetNativeEntryPointData() const
  7105. {
  7106. Assert(this->HasNativeEntryPointData());
  7107. return this->nativeEntryPointData;
  7108. }
  7109. InProcNativeEntryPointData * EntryPointInfo::GetInProcNativeEntryPointData()
  7110. {
  7111. return static_cast<InProcNativeEntryPointData *>(this->GetNativeEntryPointData());
  7112. }
  7113. #if ENABLE_OOP_NATIVE_CODEGEN
  7114. OOPNativeEntryPointData * EntryPointInfo::GetOOPNativeEntryPointData()
  7115. {
  7116. return static_cast<OOPNativeEntryPointData *>(this->GetNativeEntryPointData());
  7117. }
  7118. #endif
  7119. void EntryPointInfo::EnsureIsReadyToCall()
  7120. {
  7121. ProcessJitTransferData();
  7122. #if ENABLE_OOP_NATIVE_CODEGEN
  7123. #if !FLOATVAR
  7124. if (JITManager::GetJITManager()->IsOOPJITEnabled())
  7125. {
  7126. this->GetOOPNativeEntryPointData()->ProcessNumberPageSegments(GetScriptContext());
  7127. }
  7128. #endif
  7129. #endif
  7130. }
  7131. void EntryPointInfo::SetCodeGenRecorded(Js::JavascriptMethod thunkAddress, Js::JavascriptMethod nativeAddress, ptrdiff_t codeSize, void * validationCookie)
  7132. {
  7133. Assert(this->GetState() == CodeGenQueued);
  7134. Assert(codeSize > 0);
  7135. this->GetNativeEntryPointData()->RecordNativeCode(thunkAddress, nativeAddress, codeSize, validationCookie);
  7136. this->state = CodeGenRecorded;
  7137. #ifdef PERF_COUNTERS
  7138. this->OnRecorded();
  7139. #endif
  7140. }
  7141. void EntryPointInfo::SetCodeGenDone()
  7142. {
  7143. Assert(this->GetState() == CodeGenRecorded);
  7144. this->state = CodeGenDone;
  7145. this->workItem = nullptr;
  7146. if (this->IsLoopBody())
  7147. {
  7148. this->GetFunctionBody()->SetHasDoneLoopBodyCodeGen(true);
  7149. }
  7150. }
  7151. void EntryPointInfo::ProcessJitTransferData()
  7152. {
  7153. Assert(!IsCleanedUp());
  7154. auto jitTransferData = GetJitTransferData();
  7155. if (jitTransferData == nullptr)
  7156. {
  7157. return;
  7158. }
  7159. class AutoCleanup
  7160. {
  7161. EntryPointInfo *entryPointInfo;
  7162. public:
  7163. AutoCleanup(EntryPointInfo *entryPointInfo) : entryPointInfo(entryPointInfo)
  7164. {
  7165. }
  7166. void Done()
  7167. {
  7168. entryPointInfo = nullptr;
  7169. }
  7170. ~AutoCleanup()
  7171. {
  7172. if (entryPointInfo)
  7173. {
  7174. entryPointInfo->OnNativeCodeInstallFailure();
  7175. }
  7176. }
  7177. } autoCleanup(this);
  7178. ScriptContext* scriptContext = GetScriptContext();
  7179. if (jitTransferData->GetIsReady())
  7180. {
  7181. PinTypeRefs(scriptContext);
  7182. InstallGuards(scriptContext);
  7183. }
  7184. FreeJitTransferData();
  7185. autoCleanup.Done();
  7186. }
  7187. void EntryPointInfo::OnNativeCodeInstallFailure()
  7188. {
  7189. // If more data is transferred from the background thread to the main thread in ProcessJitTransferData,
  7190. // corresponding fields on the entryPointInfo should be rolled back here.
  7191. this->nativeEntryPointData->ClearTypeRefsAndGuards(GetScriptContext());
  7192. this->ResetOnNativeCodeInstallFailure();
  7193. }
  7194. #ifdef FIELD_ACCESS_STATS
  7195. FieldAccessStats* EntryPointInfo::EnsureFieldAccessStats(Recycler* recycler)
  7196. {
  7197. if (this->fieldAccessStats == nullptr)
  7198. {
  7199. this->fieldAccessStats = RecyclerNew(recycler, FieldAccessStats);
  7200. }
  7201. return this->fieldAccessStats;
  7202. }
  7203. #endif
  7204. void EntryPointInfo::PinTypeRefs(ScriptContext* scriptContext)
  7205. {
  7206. NativeEntryPointData * nativeEntryPointData = this->GetNativeEntryPointData();
  7207. JitTransferData * jitTransferData = nativeEntryPointData->GetJitTransferData();
  7208. Assert(jitTransferData != nullptr && jitTransferData->GetIsReady());
  7209. Recycler* recycler = scriptContext->GetRecycler();
  7210. if (jitTransferData->GetRuntimeTypeRefs() != nullptr)
  7211. {
  7212. // Copy pinned types from a heap allocated array created on the background thread
  7213. // to a recycler allocated array which will live as long as this EntryPointInfo.
  7214. // The original heap allocated array will be freed at the end of NativeCodeGenerator::CheckCodeGenDone
  7215. void** jitPinnedTypeRefs = jitTransferData->GetRuntimeTypeRefs();
  7216. size_t jitPinnedTypeRefCount = jitTransferData->GetRuntimeTypeRefCount();
  7217. nativeEntryPointData->PinTypeRefs(recycler, jitPinnedTypeRefCount, jitPinnedTypeRefs);
  7218. }
  7219. }
  7220. void EntryPointInfo::InstallGuards(ScriptContext* scriptContext)
  7221. {
  7222. NativeEntryPointData * nativeEntryPointData = this->GetNativeEntryPointData();
  7223. JitTransferData * jitTransferData = this->GetNativeEntryPointData()->GetJitTransferData();
  7224. Assert(jitTransferData != nullptr && jitTransferData->GetIsReady());
  7225. for (int i = 0; i < jitTransferData->lazyBailoutPropertyCount; i++)
  7226. {
  7227. Assert(jitTransferData->lazyBailoutProperties != nullptr);
  7228. Js::PropertyId propertyId = jitTransferData->lazyBailoutProperties[i];
  7229. Js::PropertyGuard* sharedPropertyGuard = nullptr;
  7230. bool hasSharedPropertyGuard = nativeEntryPointData->TryGetSharedPropertyGuard(propertyId, sharedPropertyGuard);
  7231. Assert(hasSharedPropertyGuard);
  7232. bool isValid = hasSharedPropertyGuard && sharedPropertyGuard->IsValid();
  7233. if (isValid)
  7234. {
  7235. scriptContext->GetThreadContext()->RegisterLazyBailout(propertyId, this);
  7236. }
  7237. else
  7238. {
  7239. OUTPUT_TRACE2(Js::LazyBailoutPhase, this->GetFunctionBody(), _u("Lazy bailout - Invalidation due to property: %s \n"), scriptContext->GetPropertyName(propertyId)->GetBuffer());
  7240. this->Invalidate(true);
  7241. return;
  7242. }
  7243. }
  7244. // in-proc JIT
  7245. if (jitTransferData->equivalentTypeGuardCount > 0)
  7246. {
  7247. Assert(jitTransferData->equivalentTypeGuardOffsets == nullptr);
  7248. Assert(jitTransferData->equivalentTypeGuards != nullptr);
  7249. int guardCount = jitTransferData->equivalentTypeGuardCount;
  7250. JitEquivalentTypeGuard** guards = jitTransferData->equivalentTypeGuards;
  7251. EquivalentTypeCache * cache = nativeEntryPointData->EnsureEquivalentTypeCache(guardCount, scriptContext, this);
  7252. for (JitEquivalentTypeGuard** guard = guards; guard < guards + guardCount; guard++)
  7253. {
  7254. EquivalentTypeCache* oldCache = (*guard)->GetCache();
  7255. // Copy the contents of the heap-allocated cache to the recycler-allocated version to make sure the types are
  7256. // kept alive. Allow the properties pointer to refer to the heap-allocated arrays. It will stay alive as long
  7257. // as the entry point is alive, and property entries contain no pointers to other recycler allocated objects.
  7258. (*cache) = (*oldCache);
  7259. // Set the recycler-allocated cache on the (heap-allocated) guard.
  7260. (*guard)->SetCache(cache);
  7261. for (uint i = 0; i < EQUIVALENT_TYPE_CACHE_SIZE; i++)
  7262. {
  7263. if((*cache).types[i] != nullptr)
  7264. {
  7265. (*cache).types[i]->SetHasBeenCached();
  7266. }
  7267. else
  7268. {
  7269. #ifdef DEBUG
  7270. for (uint __i = i; __i < EQUIVALENT_TYPE_CACHE_SIZE; __i++)
  7271. { Assert((*cache).types[__i] == nullptr); }
  7272. #endif
  7273. break; // type array must be shrinked.
  7274. }
  7275. }
  7276. cache++;
  7277. }
  7278. }
  7279. #if ENABLE_OOP_NATIVE_CODEGEN
  7280. if (jitTransferData->equivalentTypeGuardOffsets)
  7281. {
  7282. // InstallGuards
  7283. int guardCount = jitTransferData->equivalentTypeGuardOffsets->count;
  7284. EquivalentTypeCache* cache = this->nativeEntryPointData->EnsureEquivalentTypeCache(guardCount, scriptContext, this);
  7285. char * nativeDataBuffer = this->GetOOPNativeEntryPointData()->GetNativeDataBuffer();
  7286. for (int i = 0; i < guardCount; i++)
  7287. {
  7288. auto& cacheIDL = jitTransferData->equivalentTypeGuardOffsets->guards[i].cache;
  7289. auto guardOffset = jitTransferData->equivalentTypeGuardOffsets->guards[i].offset;
  7290. JitEquivalentTypeGuard* guard = (JitEquivalentTypeGuard*)(nativeDataBuffer + guardOffset);
  7291. cache[i].guard = guard;
  7292. cache[i].hasFixedValue = cacheIDL.hasFixedValue != 0;
  7293. cache[i].isLoadedFromProto = cacheIDL.isLoadedFromProto != 0;
  7294. cache[i].nextEvictionVictim = cacheIDL.nextEvictionVictim;
  7295. cache[i].record.propertyCount = cacheIDL.record.propertyCount;
  7296. cache[i].record.properties = (EquivalentPropertyEntry*)(nativeDataBuffer + cacheIDL.record.propertyOffset);
  7297. for (int j = 0; j < EQUIVALENT_TYPE_CACHE_SIZE; j++)
  7298. {
  7299. cache[i].types[j] = (Js::Type*)cacheIDL.types[j];
  7300. }
  7301. guard->SetCache(&cache[i]);
  7302. }
  7303. }
  7304. // OOP JIT
  7305. if (jitTransferData->typeGuardTransferData.entries != nullptr)
  7306. {
  7307. int propertyGuardCount = jitTransferData->typeGuardTransferData.propertyGuardCount;
  7308. Field(FakePropertyGuardWeakReference*) * propertyGuardWeakRefs = this->nativeEntryPointData->EnsurePropertyGuardWeakRefs(propertyGuardCount, scriptContext->GetRecycler());
  7309. ThreadContext* threadContext = scriptContext->GetThreadContext();
  7310. auto next = &jitTransferData->typeGuardTransferData.entries;
  7311. while (*next)
  7312. {
  7313. Js::PropertyId propertyId = (*next)->propId;
  7314. Js::PropertyGuard* sharedPropertyGuard = nullptr;
  7315. // We use the shared guard created during work item creation to ensure that the condition we assumed didn't change while
  7316. // we were JIT-ing. If we don't have a shared property guard for this property then we must not need to protect it,
  7317. // because it exists on the instance. Unfortunately, this means that if we have a bug and fail to create a shared
  7318. // guard for some property during work item creation, we won't find out about it here.
  7319. bool isNeeded = nativeEntryPointData->TryGetSharedPropertyGuard(propertyId, sharedPropertyGuard);
  7320. bool isValid = isNeeded ? sharedPropertyGuard->IsValid() : false;
  7321. if (isNeeded)
  7322. {
  7323. char * nativeDataBuffer = this->GetOOPNativeEntryPointData()->GetNativeDataBuffer();
  7324. for (unsigned int i = 0; i < (*next)->guardsCount; i++)
  7325. {
  7326. Js::JitIndexedPropertyGuard* guard = (Js::JitIndexedPropertyGuard*)(nativeDataBuffer + (*next)->guardOffsets[i]);
  7327. int guardIndex = guard->GetIndex();
  7328. Assert(guardIndex >= 0 && guardIndex < propertyGuardCount);
  7329. // We use the shared guard here to make sure the conditions we assumed didn't change while we were JIT-ing.
  7330. // If they did, we proactively invalidate the guard here, so that we bail out if we try to call this code.
  7331. if (isValid)
  7332. {
  7333. auto propertyGuardWeakRef = propertyGuardWeakRefs[guardIndex];
  7334. if (propertyGuardWeakRef == nullptr)
  7335. {
  7336. propertyGuardWeakRef = Js::FakePropertyGuardWeakReference::New(scriptContext->GetRecycler(), guard);
  7337. propertyGuardWeakRefs[guardIndex] = propertyGuardWeakRef;
  7338. }
  7339. Assert(propertyGuardWeakRef->Get() == guard);
  7340. threadContext->RegisterUniquePropertyGuard(propertyId, propertyGuardWeakRef);
  7341. }
  7342. else
  7343. {
  7344. guard->Invalidate();
  7345. }
  7346. }
  7347. }
  7348. *next = (*next)->next;
  7349. }
  7350. }
  7351. #endif
  7352. // in-proc JIT
  7353. // The propertyGuardsByPropertyId structure is temporary and serves only to register the type guards for the correct
  7354. // properties. If we've done code gen for this EntryPointInfo, typePropertyGuardsByPropertyId will have been used and nulled out.
  7355. if (jitTransferData->propertyGuardsByPropertyId != nullptr)
  7356. {
  7357. int propertyGuardCount = jitTransferData->propertyGuardCount;
  7358. Field(FakePropertyGuardWeakReference*) * propertyGuardWeakRefs = nativeEntryPointData->EnsurePropertyGuardWeakRefs(propertyGuardCount, scriptContext->GetRecycler());
  7359. ThreadContext* threadContext = scriptContext->GetThreadContext();
  7360. Js::TypeGuardTransferEntry* entry = jitTransferData->propertyGuardsByPropertyId;
  7361. while (entry->propertyId != Js::Constants::NoProperty)
  7362. {
  7363. Js::PropertyId propertyId = entry->propertyId;
  7364. Js::PropertyGuard* sharedPropertyGuard = nullptr;
  7365. // We use the shared guard created during work item creation to ensure that the condition we assumed didn't change while
  7366. // we were JIT-ing. If we don't have a shared property guard for this property then we must not need to protect it,
  7367. // because it exists on the instance. Unfortunately, this means that if we have a bug and fail to create a shared
  7368. // guard for some property during work item creation, we won't find out about it here.
  7369. bool isNeeded = nativeEntryPointData->TryGetSharedPropertyGuard(propertyId, sharedPropertyGuard);
  7370. bool isValid = isNeeded ? sharedPropertyGuard->IsValid() : false;
  7371. int entryGuardIndex = 0;
  7372. while (entry->guards[entryGuardIndex] != nullptr)
  7373. {
  7374. if (isNeeded)
  7375. {
  7376. Js::JitIndexedPropertyGuard* guard = entry->guards[entryGuardIndex];
  7377. int guardIndex = guard->GetIndex();
  7378. Assert(guardIndex >= 0 && guardIndex < propertyGuardCount);
  7379. // We use the shared guard here to make sure the conditions we assumed didn't change while we were JIT-ing.
  7380. // If they did, we proactively invalidate the guard here, so that we bail out if we try to call this code.
  7381. if (isValid)
  7382. {
  7383. auto propertyGuardWeakRef = propertyGuardWeakRefs[guardIndex];
  7384. if (propertyGuardWeakRef == nullptr)
  7385. {
  7386. propertyGuardWeakRef = Js::FakePropertyGuardWeakReference::New(scriptContext->GetRecycler(), guard);
  7387. propertyGuardWeakRefs[guardIndex] = propertyGuardWeakRef;
  7388. }
  7389. Assert(propertyGuardWeakRef->Get() == guard);
  7390. threadContext->RegisterUniquePropertyGuard(propertyId, propertyGuardWeakRef);
  7391. }
  7392. else
  7393. {
  7394. guard->Invalidate();
  7395. }
  7396. }
  7397. entryGuardIndex++;
  7398. }
  7399. entry = reinterpret_cast<Js::TypeGuardTransferEntry*>(&entry->guards[++entryGuardIndex]);
  7400. }
  7401. }
  7402. // The ctorCacheGuardsByPropertyId structure is temporary and serves only to register the constructor cache guards for the correct
  7403. // properties. If we've done code gen for this EntryPointInfo, ctorCacheGuardsByPropertyId will have been used and nulled out.
  7404. // Unlike type property guards, constructor cache guards use the live constructor caches associated with function objects. These are
  7405. // recycler allocated and are kept alive by the constructorCaches field, where they were inserted during work item creation.
  7406. // OOP JIT
  7407. if (jitTransferData->ctorCacheTransferData.entries != nullptr)
  7408. {
  7409. ThreadContext* threadContext = scriptContext->GetThreadContext();
  7410. CtorCacheTransferEntryIDL ** entries = jitTransferData->ctorCacheTransferData.entries;
  7411. for (uint i = 0; i < jitTransferData->ctorCacheTransferData.ctorCachesCount; ++i)
  7412. {
  7413. Js::PropertyId propertyId = entries[i]->propId;
  7414. Js::PropertyGuard* sharedPropertyGuard = nullptr;
  7415. // We use the shared guard created during work item creation to ensure that the condition we assumed didn't change while
  7416. // we were JIT-ing. If we don't have a shared property guard for this property then we must not need to protect it,
  7417. // because it exists on the instance. Unfortunately, this means that if we have a bug and fail to create a shared
  7418. // guard for some property during work item creation, we won't find out about it here.
  7419. bool isNeeded = nativeEntryPointData->TryGetSharedPropertyGuard(propertyId, sharedPropertyGuard);
  7420. bool isValid = isNeeded ? sharedPropertyGuard->IsValid() : false;
  7421. if (isNeeded)
  7422. {
  7423. for (uint j = 0; j < entries[i]->cacheCount; ++j)
  7424. {
  7425. Js::ConstructorCache* cache = (Js::ConstructorCache*)(entries[i]->caches[j]);
  7426. // We use the shared cache here to make sure the conditions we assumed didn't change while we were JIT-ing.
  7427. // If they did, we proactively invalidate the cache here, so that we bail out if we try to call this code.
  7428. if (isValid)
  7429. {
  7430. threadContext->RegisterConstructorCache(propertyId, cache);
  7431. }
  7432. else
  7433. {
  7434. cache->InvalidateAsGuard();
  7435. }
  7436. }
  7437. }
  7438. }
  7439. }
  7440. if (jitTransferData->ctorCacheGuardsByPropertyId != nullptr)
  7441. {
  7442. ThreadContext* threadContext = scriptContext->GetThreadContext();
  7443. Js::CtorCacheGuardTransferEntry* entry = jitTransferData->ctorCacheGuardsByPropertyId;
  7444. while (entry->propertyId != Js::Constants::NoProperty)
  7445. {
  7446. Js::PropertyId propertyId = entry->propertyId;
  7447. Js::PropertyGuard* sharedPropertyGuard = nullptr;
  7448. // We use the shared guard created during work item creation to ensure that the condition we assumed didn't change while
  7449. // we were JIT-ing. If we don't have a shared property guard for this property then we must not need to protect it,
  7450. // because it exists on the instance. Unfortunately, this means that if we have a bug and fail to create a shared
  7451. // guard for some property during work item creation, we won't find out about it here.
  7452. bool isNeeded = nativeEntryPointData->TryGetSharedPropertyGuard(propertyId, sharedPropertyGuard);
  7453. bool isValid = isNeeded ? sharedPropertyGuard->IsValid() : false;
  7454. int entryCacheIndex = 0;
  7455. while (entry->caches[entryCacheIndex] != 0)
  7456. {
  7457. if (isNeeded)
  7458. {
  7459. Js::ConstructorCache* cache = (Js::ConstructorCache*)(entry->caches[entryCacheIndex]);
  7460. // We use the shared cache here to make sure the conditions we assumed didn't change while we were JIT-ing.
  7461. // If they did, we proactively invalidate the cache here, so that we bail out if we try to call this code.
  7462. if (isValid)
  7463. {
  7464. threadContext->RegisterConstructorCache(propertyId, cache);
  7465. }
  7466. else
  7467. {
  7468. cache->InvalidateAsGuard();
  7469. }
  7470. }
  7471. entryCacheIndex++;
  7472. }
  7473. entry = reinterpret_cast<Js::CtorCacheGuardTransferEntry*>(&entry->caches[++entryCacheIndex]);
  7474. }
  7475. }
  7476. if (PHASE_ON(Js::FailNativeCodeInstallPhase, this->GetFunctionBody()))
  7477. {
  7478. Js::Throw::OutOfMemory();
  7479. }
  7480. }
  7481. InlineeFrameRecord* EntryPointInfo::FindInlineeFrame(void* returnAddress)
  7482. {
  7483. #if ENABLE_OOP_NATIVE_CODEGEN
  7484. if (JITManager::GetJITManager()->IsOOPJITEnabled()) // OOP JIT
  7485. {
  7486. OOPNativeEntryPointData * oopNativeEntryPointData = this->GetOOPNativeEntryPointData();
  7487. char * nativeDataBuffer = oopNativeEntryPointData->GetNativeDataBuffer();
  7488. NativeOffsetInlineeFrameRecordOffset* offsets = (NativeOffsetInlineeFrameRecordOffset*)(nativeDataBuffer + oopNativeEntryPointData->GetInlineeFrameOffsetArrayOffset());
  7489. size_t offset = (size_t)((BYTE*)returnAddress - (BYTE*)this->GetNativeAddress());
  7490. uint inlineeFrameOffsetArrayCount = oopNativeEntryPointData->GetInlineeFrameOffsetArrayCount();
  7491. if (inlineeFrameOffsetArrayCount == 0)
  7492. {
  7493. return nullptr;
  7494. }
  7495. uint fromIndex = 0;
  7496. uint toIndex = inlineeFrameOffsetArrayCount - 1;
  7497. while (fromIndex <= toIndex)
  7498. {
  7499. uint midIndex = fromIndex + (toIndex - fromIndex) / 2;
  7500. auto item = offsets[midIndex];
  7501. if (item.offset >= offset)
  7502. {
  7503. if (midIndex == 0 || (midIndex > 0 && offsets[midIndex - 1].offset < offset))
  7504. {
  7505. if (offsets[midIndex].recordOffset == NativeOffsetInlineeFrameRecordOffset::InvalidRecordOffset)
  7506. {
  7507. return nullptr;
  7508. }
  7509. else
  7510. {
  7511. return (InlineeFrameRecord*)(nativeDataBuffer + offsets[midIndex].recordOffset);
  7512. }
  7513. }
  7514. else
  7515. {
  7516. toIndex = midIndex - 1;
  7517. }
  7518. }
  7519. else
  7520. {
  7521. fromIndex = midIndex + 1;
  7522. }
  7523. }
  7524. return nullptr;
  7525. }
  7526. else
  7527. #endif
  7528. // in-proc JIT
  7529. {
  7530. InlineeFrameMap * inlineeFrameMap = this->GetInProcNativeEntryPointData()->GetInlineeFrameMap();
  7531. if (inlineeFrameMap == nullptr)
  7532. {
  7533. return nullptr;
  7534. }
  7535. size_t offset = (size_t)((BYTE*)returnAddress - (BYTE*)this->GetNativeAddress());
  7536. int index = inlineeFrameMap->BinarySearch([=](const NativeOffsetInlineeFramePair& pair, int index) {
  7537. if (pair.offset >= offset)
  7538. {
  7539. if (index == 0 || (index > 0 && inlineeFrameMap->Item(index - 1).offset < offset))
  7540. {
  7541. return 0;
  7542. }
  7543. else
  7544. {
  7545. return 1;
  7546. }
  7547. }
  7548. return -1;
  7549. });
  7550. if (index == -1)
  7551. {
  7552. return nullptr;
  7553. }
  7554. return inlineeFrameMap->Item(index).record;
  7555. }
  7556. }
  7557. void EntryPointInfo::DoLazyBailout(
  7558. BYTE **addressOfInstructionPointer,
  7559. BYTE *framePointer
  7560. #if DBG
  7561. , Js::FunctionBody *functionBody
  7562. , const PropertyRecord *propertyRecord
  7563. #endif
  7564. )
  7565. {
  7566. BYTE* instructionPointer = *addressOfInstructionPointer;
  7567. NativeEntryPointData * nativeEntryPointData = this->GetNativeEntryPointData();
  7568. Js::JavascriptMethod nativeAddress = nativeEntryPointData->GetNativeAddress();
  7569. ptrdiff_t codeSize = nativeEntryPointData->GetCodeSize();
  7570. Assert(instructionPointer > (BYTE*)nativeAddress && instructionPointer < ((BYTE*)nativeAddress + codeSize));
  7571. size_t offset = instructionPointer - (BYTE*)nativeAddress;
  7572. NativeLazyBailOutRecordList * bailOutRecordList = this->GetInProcNativeEntryPointData()->GetSortedLazyBailOutRecordList();
  7573. AssertMsg(bailOutRecordList != nullptr, "Lazy Bailout: bailOutRecordList is missing");
  7574. int found = bailOutRecordList->BinarySearch([=](const LazyBailOutRecord& record, int index)
  7575. {
  7576. if (record.offset == offset)
  7577. {
  7578. return 0;
  7579. }
  7580. else if (record.offset > offset)
  7581. {
  7582. return 1;
  7583. }
  7584. else
  7585. {
  7586. return -1;
  7587. }
  7588. });
  7589. if (found != -1)
  7590. {
  7591. auto inProcNativeEntryPointData = this->GetInProcNativeEntryPointData();
  7592. const LazyBailOutRecord& record = bailOutRecordList->Item(found);
  7593. const uint32 lazyBailOutThunkOffset = inProcNativeEntryPointData->GetLazyBailOutThunkOffset();
  7594. BYTE * const lazyBailOutThunkAddress = (BYTE *) nativeAddress + lazyBailOutThunkOffset;
  7595. // Change the instruction pointer of the frame to our thunk so that
  7596. // when execution returns back to this frame, we will execute the thunk instead
  7597. *addressOfInstructionPointer = lazyBailOutThunkAddress;
  7598. // Put the BailOutRecord corresponding to our LazyBailOut point on the pre-allocated slot on the stack
  7599. BYTE *addressOfLazyBailOutRecordSlot = framePointer + inProcNativeEntryPointData->GetLazyBailOutRecordSlotOffset();
  7600. *(reinterpret_cast<intptr_t *>(addressOfLazyBailOutRecordSlot)) = reinterpret_cast<intptr_t>(record.bailOutRecord);
  7601. if (PHASE_TRACE1(Js::LazyBailoutPhase))
  7602. {
  7603. #if DBG
  7604. Output::Print(_u("On stack lazy bailout. Property: %s Old IP: 0x%x New IP: 0x%x "), propertyRecord->GetBuffer(), instructionPointer, lazyBailOutThunkAddress);
  7605. record.Dump(functionBody);
  7606. Output::Print(_u("\n"));
  7607. #endif
  7608. }
  7609. }
  7610. else
  7611. {
  7612. AssertMsg(false, "Lazy Bailout: Address mapping missing");
  7613. }
  7614. }
  7615. void EntryPointInfo::FreeJitTransferData()
  7616. {
  7617. if (this->HasNativeEntryPointData())
  7618. {
  7619. this->GetNativeEntryPointData()->FreeJitTransferData();;
  7620. }
  7621. }
  7622. bool EntryPointInfo::ClearEquivalentTypeCaches()
  7623. {
  7624. return this->GetNativeEntryPointData()->ClearEquivalentTypeCaches(GetScriptContext()->GetRecycler());
  7625. }
  7626. bool EquivalentTypeCache::ClearUnusedTypes(Recycler *recycler)
  7627. {
  7628. bool isAnyTypeLive = false;
  7629. Assert(this->guard);
  7630. if (this->guard->IsValid())
  7631. {
  7632. if (this->guard->IsPoly())
  7633. {
  7634. JitPolyEquivalentTypeGuard * polyGuard = this->guard->AsPolyTypeCheckGuard();
  7635. for (uint8 i = 0; i < polyGuard->GetSize(); i++)
  7636. {
  7637. intptr_t value = polyGuard->GetPolyValue(i);
  7638. if (value != PropertyGuard::GuardValue::Uninitialized && value != PropertyGuard::GuardValue::Invalidated_DuringSweep)
  7639. {
  7640. Type *type = reinterpret_cast<Type*>(value);
  7641. if (!recycler->IsObjectMarked(type))
  7642. {
  7643. polyGuard->InvalidateDuringSweep(i);
  7644. }
  7645. else
  7646. {
  7647. isAnyTypeLive = true;
  7648. }
  7649. }
  7650. }
  7651. }
  7652. else
  7653. {
  7654. Type *type = reinterpret_cast<Type*>(this->guard->GetValue());
  7655. if (!recycler->IsObjectMarked(type))
  7656. {
  7657. this->guard->InvalidateDuringSweep();
  7658. }
  7659. else
  7660. {
  7661. isAnyTypeLive = true;
  7662. }
  7663. }
  7664. }
  7665. uint16 nonNullIndex = 0;
  7666. #if DBG
  7667. bool isGuardValuePresent = false;
  7668. #endif
  7669. for (int i = 0; i < EQUIVALENT_TYPE_CACHE_SIZE; i++)
  7670. {
  7671. Type *type = this->types[i];
  7672. if (type != nullptr)
  7673. {
  7674. this->types[i] = nullptr;
  7675. if (recycler->IsObjectMarked(type))
  7676. {
  7677. // compact the types array by moving non-null types
  7678. // to the beginning.
  7679. this->types[nonNullIndex++] = type;
  7680. #if DBG
  7681. if (guard->IsPoly())
  7682. {
  7683. isGuardValuePresent = true;
  7684. }
  7685. else if (this->guard->GetValue() == reinterpret_cast<intptr_t>(type))
  7686. {
  7687. isGuardValuePresent = true;
  7688. }
  7689. #endif
  7690. }
  7691. }
  7692. else
  7693. {
  7694. #ifdef DEBUG
  7695. for (int __i = i; __i < EQUIVALENT_TYPE_CACHE_SIZE; __i++)
  7696. { Assert(this->types[__i] == nullptr); }
  7697. #endif
  7698. break; // array must be shrinked already
  7699. }
  7700. }
  7701. if (nonNullIndex > 0)
  7702. {
  7703. isAnyTypeLive = true;
  7704. }
  7705. else if (guard->IsPoly())
  7706. {
  7707. if (!isAnyTypeLive)
  7708. {
  7709. guard->Invalidate();
  7710. }
  7711. }
  7712. else if (guard->IsInvalidatedDuringSweep())
  7713. {
  7714. // just mark this as actual invalidated since there are no types
  7715. // present
  7716. guard->Invalidate();
  7717. }
  7718. // verify if guard value is valid, it is present in one of the types
  7719. AssertMsg(!this->guard->IsValid() || isGuardValuePresent || nonNullIndex == 0,
  7720. "After ClearUnusedTypes, valid guard value should be one of the cached equivalent types.");
  7721. return isAnyTypeLive;
  7722. }
  7723. #endif
  7724. #if ENABLE_ENTRYPOINT_CLEANUP_TRACE
  7725. #if ENABLE_DEBUG_STACK_BACK_TRACE
  7726. void EntryPointInfo::CaptureCleanupStackTrace()
  7727. {
  7728. if (this->cleanupStack != nullptr)
  7729. {
  7730. this->cleanupStack->Delete(&NoCheckHeapAllocator::Instance);
  7731. this->cleanupStack = nullptr;
  7732. }
  7733. this->cleanupStack = StackBackTrace::Capture(&NoCheckHeapAllocator::Instance);
  7734. }
  7735. #endif
  7736. #endif
  7737. void EntryPointInfo::Finalize(bool isShutdown)
  7738. {
  7739. __super::Finalize(isShutdown);
  7740. if (!isShutdown)
  7741. {
  7742. ReleasePendingWorkItem();
  7743. }
  7744. #if ENABLE_ENTRYPOINT_CLEANUP_TRACE
  7745. this->SetCleanupReason(CleanupReason::CleanUpForFinalize);
  7746. #endif
  7747. this->Cleanup(isShutdown, false);
  7748. #if ENABLE_ENTRYPOINT_CLEANUP_TRACE
  7749. #if ENABLE_DEBUG_STACK_BACK_TRACE
  7750. if (this->cleanupStack != nullptr)
  7751. {
  7752. this->cleanupStack->Delete(&NoCheckHeapAllocator::Instance);
  7753. this->cleanupStack = nullptr;
  7754. }
  7755. #endif
  7756. #endif
  7757. this->library = nullptr;
  7758. }
  7759. void EntryPointInfo::Cleanup(bool isShutdown, bool captureCleanupStack)
  7760. {
  7761. if (this->GetState() != CleanedUp)
  7762. {
  7763. #if ENABLE_NATIVE_CODEGEN
  7764. this->OnCleanup(isShutdown);
  7765. if (this->nativeEntryPointData)
  7766. {
  7767. this->nativeEntryPointData->Cleanup(GetScriptContext(), isShutdown, false);
  7768. this->nativeEntryPointData = nullptr;
  7769. }
  7770. #endif // ENABLE_NATIVE_CODEGEN
  7771. // This is how we set the CleanedUp state
  7772. this->workItem = nullptr;
  7773. this->library = nullptr;
  7774. this->state = CleanedUp;
  7775. #if ENABLE_ENTRYPOINT_CLEANUP_TRACE
  7776. #if ENABLE_DEBUG_CONFIG_OPTIONS
  7777. #if !DBG
  7778. captureCleanupStack = captureCleanupStack && Js::Configuration::Global.flags.FreTestDiagMode;
  7779. #endif
  7780. #if ENABLE_DEBUG_STACK_BACK_TRACE
  7781. if (captureCleanupStack)
  7782. {
  7783. this->CaptureCleanupStackTrace();
  7784. }
  7785. #endif
  7786. #endif
  7787. #endif
  7788. #if DEBUG
  7789. const unsigned char* rpcData = serializedRpcData;
  7790. HeapDeleteArray(serializedRpcDataSize, rpcData);
  7791. serializedRpcDataSize = 0;
  7792. serializedRpcData = nullptr;
  7793. #endif
  7794. }
  7795. }
  7796. void EntryPointInfo::Reset(bool resetStateToNotScheduled)
  7797. {
  7798. Assert(this->GetState() != CleanedUp);
  7799. this->workItem = nullptr;
  7800. #if ENABLE_NATIVE_CODEGEN
  7801. if (this->nativeEntryPointData)
  7802. {
  7803. this->nativeEntryPointData->Cleanup(GetScriptContext(), false, true);
  7804. this->nativeEntryPointData = nullptr;
  7805. }
  7806. #endif
  7807. // Set the state to NotScheduled only if the call to Reset is not because of JIT cap being reached
  7808. if (resetStateToNotScheduled)
  7809. {
  7810. this->state = NotScheduled;
  7811. }
  7812. }
  7813. #if ENABLE_NATIVE_CODEGEN
  7814. // This function needs review when we enable lazy bailouts-
  7815. // Is calling Reset enough? Does Reset sufficiently resets the state of the entryPointInfo?
  7816. void EntryPointInfo::ResetOnLazyBailoutFailure()
  7817. {
  7818. Assert(PHASE_ON1(Js::LazyBailoutPhase));
  7819. // Reset the entry point upon a lazy bailout.
  7820. this->Reset(true);
  7821. this->jsMethod = nullptr;
  7822. }
  7823. #endif
  7824. #ifdef ASMJS_PLAT
  7825. void EntryPointInfo::SetIsTJMode(bool value)
  7826. {
  7827. Assert(this->GetIsAsmJSFunction());
  7828. mIsTemplatizedJitMode = value;
  7829. }
  7830. bool EntryPointInfo::GetIsTJMode()const
  7831. {
  7832. return mIsTemplatizedJitMode;
  7833. };
  7834. // set code size, used by TJ to set the code size
  7835. void EntryPointInfo::SetTJCodeSize(ptrdiff_t size)
  7836. {
  7837. Assert(isAsmJsFunction);
  7838. // TODO: We don't need the whole NativeEntryPointData to just hold just the code and size for TJ mode
  7839. this->EnsureNativeEntryPointData()->SetTJCodeSize(size);
  7840. }
  7841. void EntryPointInfo::SetTJNativeAddress(Js::JavascriptMethod address, void * validationCookie)
  7842. {
  7843. Assert(isAsmJsFunction);
  7844. // TODO: We don't need the whole NativeEntryPointData to just hold just the code and size for TJ mode
  7845. this->EnsureNativeEntryPointData()->SetTJNativeAddress(address, validationCookie);
  7846. }
  7847. #endif
  7848. //End AsmJS Support
  7849. #ifdef PERF_COUNTERS
  7850. void FunctionEntryPointInfo::OnRecorded()
  7851. {
  7852. PERF_COUNTER_ADD(Code, TotalNativeCodeSize, GetCodeSize());
  7853. PERF_COUNTER_ADD(Code, FunctionNativeCodeSize, GetCodeSize());
  7854. PERF_COUNTER_ADD(Code, DynamicNativeCodeSize, GetCodeSize());
  7855. }
  7856. #endif
  7857. FunctionEntryPointInfo::FunctionEntryPointInfo(FunctionProxy * functionProxy, Js::JavascriptMethod method, ThreadContext* context) :
  7858. EntryPointInfo(method, functionProxy->GetScriptContext()->GetLibrary(), context),
  7859. localVarSlotsOffset(Js::Constants::InvalidOffset),
  7860. localVarChangedOffset(Js::Constants::InvalidOffset),
  7861. callsCount(0),
  7862. jitMode(ExecutionMode::Interpreter),
  7863. functionProxy(functionProxy),
  7864. nextEntryPoint(nullptr)
  7865. {
  7866. }
  7867. #if ENABLE_NATIVE_CODEGEN
  7868. ExecutionMode FunctionEntryPointInfo::GetJitMode() const
  7869. {
  7870. return jitMode;
  7871. }
  7872. void FunctionEntryPointInfo::SetJitMode(const ExecutionMode jitMode)
  7873. {
  7874. Assert(jitMode == ExecutionMode::SimpleJit || jitMode == ExecutionMode::FullJit);
  7875. this->jitMode = jitMode;
  7876. }
  7877. #endif
  7878. bool FunctionEntryPointInfo::ExecutedSinceCallCountCollection() const
  7879. {
  7880. return this->callsCount != this->lastCallsCount;
  7881. }
  7882. void FunctionEntryPointInfo::CollectCallCounts()
  7883. {
  7884. this->lastCallsCount = this->callsCount;
  7885. }
  7886. void FunctionEntryPointInfo::ReleasePendingWorkItem()
  7887. {
  7888. // Do this outside of Cleanup since cleanup can be called from the background thread
  7889. // We remove any work items corresponding to the function body being reclaimed
  7890. // so that the background thread doesn't try to use them. ScriptContext != null => this
  7891. // is a function entry point
  7892. // In general this is not needed for loop bodies since loop bodies aren't in the low priority
  7893. // queue, they should be jitted before the entry point is finalized
  7894. if (!this->IsNotScheduled() && !this->IsCleanedUp())
  7895. {
  7896. #if defined(_M_ARM32_OR_ARM64)
  7897. // On ARM machines, order of writes is not guaranteed while reading data from another processor
  7898. // So we need to have a memory barrier here in order to make sure that the work item is consistent
  7899. MemoryBarrier();
  7900. #endif
  7901. CodeGenWorkItem* workItem = this->GetWorkItem();
  7902. if (workItem != nullptr)
  7903. {
  7904. Assert(this->library != nullptr);
  7905. #if ENABLE_NATIVE_CODEGEN
  7906. TryReleaseNonHiPriWorkItem(this->library->GetScriptContext(), workItem);
  7907. #endif
  7908. }
  7909. }
  7910. }
  7911. FunctionBody *FunctionEntryPointInfo::GetFunctionBody() const
  7912. {
  7913. return functionProxy->GetFunctionBody();
  7914. }
  7915. #if ENABLE_NATIVE_CODEGEN
  7916. void EntryPointInfo::CleanupNativeCode(ScriptContext * scriptContext)
  7917. {
  7918. if (this->jsMethod == this->GetNativeEntrypoint())
  7919. {
  7920. #if DBG
  7921. // tag the jsMethod in case the native address is reused in recycler and create a false positive
  7922. // not checking validationCookie because this can happen while debugger attaching, native address
  7923. // are batch freed through deleting NativeCodeGenerator
  7924. this->jsMethod = (Js::JavascriptMethod)((intptr_t)this->jsMethod | 1);
  7925. #else
  7926. this->jsMethod = nullptr;
  7927. #endif
  7928. }
  7929. }
  7930. #endif
  7931. void FunctionEntryPointInfo::OnCleanup(bool isShutdown)
  7932. {
  7933. if (this->IsCodeGenDone())
  7934. {
  7935. Assert(this->functionProxy->GetFunctionInfo()->HasBody());
  7936. #if ENABLE_NATIVE_CODEGEN
  7937. if (this->IsNativeEntryPointProcessed())
  7938. {
  7939. JS_ETW(EtwTrace::LogMethodNativeUnloadEvent(this->functionProxy->GetFunctionBody(), this));
  7940. }
  7941. #endif
  7942. FunctionBody* functionBody = this->functionProxy->GetFunctionBody();
  7943. #ifdef ASMJS_PLAT
  7944. if (this->GetIsTJMode())
  7945. {
  7946. // release LoopHeaders here if the entrypointInfo is TJ
  7947. this->GetFunctionBody()->ReleaseLoopHeaders();
  7948. }
  7949. #endif
  7950. if(functionBody->GetSimpleJitEntryPointInfo() == this)
  7951. {
  7952. functionBody->SetSimpleJitEntryPointInfo(nullptr);
  7953. }
  7954. #if ENABLE_NATIVE_CODEGEN
  7955. CleanupNativeCode(this->functionProxy->GetScriptContext());
  7956. #endif
  7957. }
  7958. this->functionProxy = nullptr;
  7959. }
  7960. #if ENABLE_NATIVE_CODEGEN
  7961. void FunctionEntryPointInfo::ResetOnNativeCodeInstallFailure()
  7962. {
  7963. this->functionProxy->MapFunctionObjectTypes([&](ScriptFunctionType* functionType)
  7964. {
  7965. Assert(functionType->GetTypeId() == TypeIds_Function);
  7966. if (functionType->GetEntryPointInfo() == this)
  7967. {
  7968. if (!this->GetIsAsmJSFunction())
  7969. {
  7970. functionType->SetEntryPoint(GetCheckCodeGenThunk());
  7971. }
  7972. #ifdef ASMJS_PLAT
  7973. else
  7974. {
  7975. functionType->SetEntryPoint(GetCheckAsmJsCodeGenThunk());
  7976. }
  7977. #endif
  7978. }
  7979. });
  7980. }
  7981. void FunctionEntryPointInfo::EnterExpirableCollectMode()
  7982. {
  7983. this->lastCallsCount = this->callsCount;
  7984. // For code that is not jitted yet we don't want to expire since there is nothing to free here
  7985. if (this->IsCodeGenPending())
  7986. {
  7987. this->SetIsObjectUsed();
  7988. }
  7989. }
  7990. void FunctionEntryPointInfo::Invalidate(bool prolongEntryPoint)
  7991. {
  7992. Assert(!this->functionProxy->IsDeferred());
  7993. FunctionBody* functionBody = this->functionProxy->GetFunctionBody();
  7994. Assert(this != functionBody->GetSimpleJitEntryPointInfo());
  7995. // We may have got here following OOM in ProcessJitTransferData. Free any data we have
  7996. // to reduce the chance of another OOM below.
  7997. this->FreeJitTransferData();
  7998. FunctionEntryPointInfo* entryPoint = functionBody->GetDefaultFunctionEntryPointInfo();
  7999. if (entryPoint->IsCodeGenPending())
  8000. {
  8001. OUTPUT_TRACE(Js::LazyBailoutPhase, _u("Skipping creating new entrypoint as one is already pending\n"));
  8002. }
  8003. else
  8004. {
  8005. class AutoCleanup
  8006. {
  8007. EntryPointInfo *entryPointInfo;
  8008. public:
  8009. AutoCleanup(EntryPointInfo *entryPointInfo) : entryPointInfo(entryPointInfo)
  8010. {
  8011. }
  8012. void Done()
  8013. {
  8014. entryPointInfo = nullptr;
  8015. }
  8016. ~AutoCleanup()
  8017. {
  8018. if (entryPointInfo)
  8019. {
  8020. entryPointInfo->ResetOnLazyBailoutFailure();
  8021. }
  8022. }
  8023. } autoCleanup(this);
  8024. entryPoint = functionBody->CreateNewDefaultEntryPoint();
  8025. GenerateFunction(functionBody->GetScriptContext()->GetNativeCodeGenerator(), functionBody, /*function*/ nullptr);
  8026. autoCleanup.Done();
  8027. }
  8028. this->functionProxy->MapFunctionObjectTypes([&](ScriptFunctionType* functionType)
  8029. {
  8030. Assert(functionType->GetTypeId() == TypeIds_Function);
  8031. if (functionType->GetEntryPointInfo() == this)
  8032. {
  8033. functionType->SetEntryPointInfo(entryPoint);
  8034. functionType->SetEntryPoint(this->functionProxy->GetDirectEntryPoint(entryPoint));
  8035. }
  8036. });
  8037. if (!prolongEntryPoint)
  8038. {
  8039. ThreadContext* threadContext = this->functionProxy->GetScriptContext()->GetThreadContext();
  8040. threadContext->QueueFreeOldEntryPointInfoIfInScript(this);
  8041. }
  8042. }
  8043. void FunctionEntryPointInfo::Expire()
  8044. {
  8045. if (this->lastCallsCount != this->callsCount || !this->IsNativeEntryPointProcessed() || this->IsCleanedUp())
  8046. {
  8047. return;
  8048. }
  8049. ThreadContext* threadContext = this->functionProxy->GetScriptContext()->GetThreadContext();
  8050. Assert(!this->functionProxy->IsDeferred());
  8051. FunctionBody* functionBody = this->functionProxy->GetFunctionBody();
  8052. FunctionEntryPointInfo *simpleJitEntryPointInfo = functionBody->GetSimpleJitEntryPointInfo();
  8053. const bool expiringSimpleJitEntryPointInfo = simpleJitEntryPointInfo == this;
  8054. if(expiringSimpleJitEntryPointInfo)
  8055. {
  8056. if(functionBody->GetExecutionMode() != ExecutionMode::FullJit)
  8057. {
  8058. // Don't expire simple JIT code until the transition to full JIT
  8059. return;
  8060. }
  8061. simpleJitEntryPointInfo = nullptr;
  8062. functionBody->SetSimpleJitEntryPointInfo(nullptr);
  8063. }
  8064. try
  8065. {
  8066. AUTO_NESTED_HANDLED_EXCEPTION_TYPE(ExceptionType_OutOfMemory);
  8067. FunctionEntryPointInfo* newEntryPoint = nullptr;
  8068. FunctionEntryPointInfo *const defaultEntryPointInfo = functionBody->GetDefaultFunctionEntryPointInfo();
  8069. if(this == defaultEntryPointInfo)
  8070. {
  8071. if(simpleJitEntryPointInfo)
  8072. {
  8073. newEntryPoint = simpleJitEntryPointInfo;
  8074. functionBody->SetDefaultFunctionEntryPointInfo(simpleJitEntryPointInfo, newEntryPoint->GetNativeEntrypoint());
  8075. functionBody->ResetSimpleJitLimitAndCallCount();
  8076. }
  8077. #ifdef ASMJS_PLAT
  8078. else if (functionBody->GetIsAsmJsFunction())
  8079. {
  8080. // the new entrypoint will be set to interpreter
  8081. newEntryPoint = functionBody->CreateNewDefaultEntryPoint();
  8082. newEntryPoint->SetIsAsmJSFunction(true);
  8083. newEntryPoint->jsMethod = AsmJsDefaultEntryThunk;
  8084. functionBody->SetIsAsmJsFullJitScheduled(false);
  8085. functionBody->SetDefaultInterpreterExecutionMode();
  8086. this->functionProxy->SetOriginalEntryPoint(AsmJsDefaultEntryThunk);
  8087. }
  8088. #endif
  8089. else
  8090. {
  8091. newEntryPoint = functionBody->CreateNewDefaultEntryPoint();
  8092. functionBody->ReinitializeExecutionModeAndLimits();
  8093. #if ENABLE_NATIVE_CODEGEN
  8094. // In order for the function to ever get JIT again, we need to call GenerateFunction now
  8095. if (!PHASE_OFF(Js::BackEndPhase, functionBody) && !functionBody->GetScriptContext()->GetConfig()->IsNoNative())
  8096. {
  8097. GenerateFunction(functionBody->GetScriptContext()->GetNativeCodeGenerator(), functionBody);
  8098. }
  8099. #endif
  8100. }
  8101. functionBody->TraceExecutionMode("JitCodeExpired");
  8102. }
  8103. else
  8104. {
  8105. newEntryPoint = defaultEntryPointInfo;
  8106. }
  8107. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Expiring 0x%p\n"), this);
  8108. this->functionProxy->MapFunctionObjectTypes([&] (ScriptFunctionType* functionType)
  8109. {
  8110. Assert(functionType->GetTypeId() == TypeIds_Function);
  8111. if (functionType->GetEntryPointInfo() == this)
  8112. {
  8113. OUTPUT_TRACE(Js::ExpirableCollectPhase, _u("Type 0x%p uses this entry point- switching to default entry point\n"), this);
  8114. functionType->SetEntryPointInfo(newEntryPoint);
  8115. // we are allowed to replace the entry point on the type only if it's
  8116. // directly using the jitted code or a type is referencing this entry point
  8117. // but the entry point hasn't been called since the codegen thunk was installed on it
  8118. if (functionType->GetEntryPoint() == functionProxy->GetDirectEntryPoint(this) || IsIntermediateCodeGenThunk(functionType->GetEntryPoint()))
  8119. {
  8120. functionType->SetEntryPoint(this->functionProxy->GetDirectEntryPoint(newEntryPoint));
  8121. }
  8122. }
  8123. else
  8124. {
  8125. Assert(!functionType->GetEntryPointInfo()->IsFunctionEntryPointInfo() ||
  8126. ((FunctionEntryPointInfo*)functionType->GetEntryPointInfo())->IsCleanedUp()
  8127. || functionType->GetEntryPoint() != this->GetNativeEntrypoint());
  8128. }
  8129. });
  8130. if(expiringSimpleJitEntryPointInfo)
  8131. {
  8132. // We could have just created a new entry point info that is using the simple JIT code. An allocation may have
  8133. // triggered shortly after, resulting in expiring the simple JIT entry point info. Update any entry point infos
  8134. // that are using the simple JIT code, and update the original entry point as necessary as well.
  8135. const JavascriptMethod newOriginalEntryPoint =
  8136. functionBody->GetDynamicInterpreterEntryPoint()
  8137. ? reinterpret_cast<JavascriptMethod>(
  8138. InterpreterThunkEmitter::ConvertToEntryPoint(functionBody->GetDynamicInterpreterEntryPoint()))
  8139. : DefaultEntryThunk;
  8140. const JavascriptMethod currentThunk = functionBody->GetScriptContext()->CurrentThunk;
  8141. const JavascriptMethod newDirectEntryPoint =
  8142. currentThunk == DefaultEntryThunk ? newOriginalEntryPoint : currentThunk;
  8143. const JavascriptMethod simpleJitNativeAddress = GetNativeEntrypoint();
  8144. functionBody->MapEntryPoints([&](const int entryPointIndex, FunctionEntryPointInfo *const entryPointInfo)
  8145. {
  8146. if(entryPointInfo != this && entryPointInfo->jsMethod == simpleJitNativeAddress)
  8147. {
  8148. entryPointInfo->jsMethod = newDirectEntryPoint;
  8149. }
  8150. });
  8151. if(functionBody->GetOriginalEntryPoint_Unchecked() == simpleJitNativeAddress)
  8152. {
  8153. functionBody->SetOriginalEntryPoint(newOriginalEntryPoint);
  8154. functionBody->VerifyOriginalEntryPoint();
  8155. }
  8156. }
  8157. threadContext->QueueFreeOldEntryPointInfoIfInScript(this);
  8158. }
  8159. catch (Js::OutOfMemoryException)
  8160. {
  8161. // If we can't allocate a new entry point, skip expiring this object
  8162. if(expiringSimpleJitEntryPointInfo)
  8163. {
  8164. simpleJitEntryPointInfo = this;
  8165. functionBody->SetSimpleJitEntryPointInfo(this);
  8166. }
  8167. }
  8168. }
  8169. #endif
  8170. #ifdef PERF_COUNTERS
  8171. void LoopEntryPointInfo::OnRecorded()
  8172. {
  8173. PERF_COUNTER_ADD(Code, TotalNativeCodeSize, GetCodeSize());
  8174. PERF_COUNTER_ADD(Code, LoopNativeCodeSize, GetCodeSize());
  8175. PERF_COUNTER_ADD(Code, DynamicNativeCodeSize, GetCodeSize());
  8176. }
  8177. #endif
  8178. FunctionBody *LoopEntryPointInfo::GetFunctionBody() const
  8179. {
  8180. return loopHeader->functionBody;
  8181. }
  8182. //End AsmJs Support
  8183. void LoopEntryPointInfo::OnCleanup(bool isShutdown)
  8184. {
  8185. #ifdef ASMJS_PLAT
  8186. if (this->IsCodeGenDone() && !this->GetIsTJMode())
  8187. #else
  8188. if (this->IsCodeGenDone())
  8189. #endif
  8190. {
  8191. JS_ETW(EtwTrace::LogLoopBodyUnloadEvent(this->loopHeader->functionBody, this,
  8192. this->loopHeader->functionBody->GetLoopNumber(this->loopHeader)));
  8193. #if ENABLE_NATIVE_CODEGEN
  8194. this->CleanupNativeCode(this->loopHeader->functionBody->GetScriptContext());
  8195. #endif
  8196. }
  8197. }
  8198. #if ENABLE_NATIVE_CODEGEN
  8199. void LoopEntryPointInfo::ResetOnNativeCodeInstallFailure()
  8200. {
  8201. // Since we call the address on the entryPointInfo for loop bodies, all we need to do is to roll back
  8202. // the fields on the entryPointInfo related to transferring data from jit thread to main thread (already
  8203. // being done in EntryPointInfo::OnNativeCodeInstallFailure). On the next loop iteration, the interpreter
  8204. // will call EntryPointInfo::EnsureIsReadyToCall and we'll try to process jit transfer data again.
  8205. }
  8206. #endif
  8207. void LoopHeader::Init( FunctionBody * functionBody )
  8208. {
  8209. // DisableJIT-TODO: Should this entire class be ifdefed out?
  8210. #if ENABLE_NATIVE_CODEGEN
  8211. this->functionBody = functionBody;
  8212. Recycler* recycler = functionBody->GetScriptContext()->GetRecycler();
  8213. // Sync entryPoints changes to etw rundown lock
  8214. auto syncObj = functionBody->GetScriptContext()->GetThreadContext()->GetFunctionBodyLock();
  8215. this->entryPoints = RecyclerNew(recycler, LoopEntryPointList, recycler, syncObj);
  8216. this->CreateEntryPoint();
  8217. #endif
  8218. }
  8219. #if ENABLE_NATIVE_CODEGEN
  8220. int LoopHeader::CreateEntryPoint()
  8221. {
  8222. ScriptContext* scriptContext = this->functionBody->GetScriptContext();
  8223. Recycler* recycler = scriptContext->GetRecycler();
  8224. LoopEntryPointInfo* entryPoint = RecyclerNew(recycler, LoopEntryPointInfo, this, scriptContext->GetLibrary());
  8225. return this->entryPoints->Add(entryPoint);
  8226. }
  8227. void LoopHeader::ReleaseEntryPoints()
  8228. {
  8229. for (int iEntryPoint = 0; iEntryPoint < this->entryPoints->Count(); iEntryPoint++)
  8230. {
  8231. LoopEntryPointInfo * entryPoint = this->entryPoints->Item(iEntryPoint);
  8232. if (entryPoint != nullptr && entryPoint->IsCodeGenDone())
  8233. {
  8234. // ReleaseEntryPoints is not called during recycler shutdown scenarios
  8235. // We also don't capture the cleanup stack since we've not seen cleanup bugs affect
  8236. // loop entry points so far. We can pass true here if this is no longer the case.
  8237. entryPoint->Cleanup(false /* isShutdown */, false /* capture cleanup stack */);
  8238. this->entryPoints->Item(iEntryPoint, nullptr);
  8239. }
  8240. }
  8241. }
  8242. #endif
  8243. #if ENABLE_DEBUG_CONFIG_OPTIONS
  8244. void FunctionBody::DumpRegStats(FunctionBody *funcBody)
  8245. {
  8246. if (funcBody->callCountStats == 0)
  8247. {
  8248. return;
  8249. }
  8250. uint loads = funcBody->regAllocLoadCount;
  8251. uint stores = funcBody->regAllocStoreCount;
  8252. if (Js::Configuration::Global.flags.NormalizeStats)
  8253. {
  8254. loads /= this->callCountStats;
  8255. stores /= this->callCountStats;
  8256. }
  8257. funcBody->DumpFullFunctionName();
  8258. Output::SkipToColumn(55);
  8259. Output::Print(_u("Calls:%6d Loads:%9d Stores:%9d Total refs:%9d\n"), this->callCountStats,
  8260. loads, stores, loads + stores);
  8261. }
  8262. #endif
  8263. Js::RegSlot FunctionBody::GetRestParamRegSlot()
  8264. {
  8265. Js::RegSlot dstRegSlot = GetConstantCount();
  8266. if (GetHasImplicitArgIns())
  8267. {
  8268. dstRegSlot += GetInParamsCount() - 1;
  8269. }
  8270. return dstRegSlot;
  8271. }
  8272. uint FunctionBody::GetNumberOfRecursiveCallSites()
  8273. {
  8274. uint recursiveInlineSpan = 0;
  8275. uint recursiveCallSiteInlineInfo = 0;
  8276. #if ENABLE_PROFILE_INFO
  8277. if (this->HasDynamicProfileInfo())
  8278. {
  8279. recursiveCallSiteInlineInfo = this->dynamicProfileInfo->GetRecursiveInlineInfo();
  8280. }
  8281. #endif
  8282. while (recursiveCallSiteInlineInfo)
  8283. {
  8284. recursiveInlineSpan += (recursiveCallSiteInlineInfo & 1);
  8285. recursiveCallSiteInlineInfo >>= 1;
  8286. }
  8287. return recursiveInlineSpan;
  8288. }
  8289. bool FunctionBody::CanInlineRecursively(uint depth, bool tryAggressive)
  8290. {
  8291. uint recursiveInlineSpan = this->GetNumberOfRecursiveCallSites();
  8292. uint minRecursiveInlineDepth = (uint)CONFIG_FLAG(RecursiveInlineDepthMin);
  8293. if (recursiveInlineSpan != this->GetProfiledCallSiteCount() || tryAggressive == false)
  8294. {
  8295. return depth < minRecursiveInlineDepth;
  8296. }
  8297. uint maxRecursiveInlineDepth = (uint)CONFIG_FLAG(RecursiveInlineDepthMax);
  8298. uint maxRecursiveBytecodeBudget = (uint)CONFIG_FLAG(RecursiveInlineThreshold);
  8299. uint numberOfAllowedFuncs = maxRecursiveBytecodeBudget / this->GetByteCodeWithoutLDACount();
  8300. uint maxDepth;
  8301. if (recursiveInlineSpan == 1)
  8302. {
  8303. maxDepth = numberOfAllowedFuncs;
  8304. }
  8305. else
  8306. {
  8307. maxDepth = (uint)ceil(log((double)((double)numberOfAllowedFuncs) / log((double)recursiveInlineSpan)));
  8308. }
  8309. maxDepth = maxDepth < minRecursiveInlineDepth ? minRecursiveInlineDepth : maxDepth;
  8310. maxDepth = maxDepth < maxRecursiveInlineDepth ? maxDepth : maxRecursiveInlineDepth;
  8311. return depth < maxDepth;
  8312. }
  8313. static const char16 LoopWStr[] = _u("Loop");
  8314. size_t FunctionBody::GetLoopBodyName(uint loopNumber, _Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars)
  8315. {
  8316. const char16* functionName = this->GetExternalDisplayName();
  8317. size_t length = wcslen(functionName) + /*length of largest int32*/ 10 + _countof(LoopWStr) + /*null*/ 1;
  8318. if (sizeInChars < length || displayName == nullptr)
  8319. {
  8320. return length;
  8321. }
  8322. int charsWritten = swprintf_s(displayName, length, _u("%s%s%u"), functionName, LoopWStr, loopNumber + 1);
  8323. Assert(charsWritten != -1);
  8324. return charsWritten + /*nullptr*/ 1;
  8325. }
  8326. void FunctionBody::MapAndSetEnvRegister(RegSlot reg)
  8327. {
  8328. Assert(!m_hasEnvRegister);
  8329. SetEnvRegister(this->MapRegSlot(reg));
  8330. }
  8331. void FunctionBody::SetEnvRegister(RegSlot reg)
  8332. {
  8333. if (reg == Constants::NoRegister)
  8334. {
  8335. m_hasEnvRegister = false;
  8336. }
  8337. else
  8338. {
  8339. m_hasEnvRegister = true;
  8340. SetCountField(CounterFields::EnvRegister, reg);
  8341. }
  8342. }
  8343. RegSlot FunctionBody::GetEnvRegister() const
  8344. {
  8345. return m_hasEnvRegister ? GetCountField(CounterFields::EnvRegister) : Constants::NoRegister;
  8346. }
  8347. void FunctionBody::MapAndSetThisRegisterForEventHandler(RegSlot reg)
  8348. {
  8349. Assert(!m_hasThisRegisterForEventHandler);
  8350. SetThisRegisterForEventHandler(this->MapRegSlot(reg));
  8351. }
  8352. void FunctionBody::SetThisRegisterForEventHandler(RegSlot reg)
  8353. {
  8354. if (reg == Constants::NoRegister)
  8355. {
  8356. m_hasThisRegisterForEventHandler = false;
  8357. }
  8358. else
  8359. {
  8360. m_hasThisRegisterForEventHandler = true;
  8361. SetCountField(CounterFields::ThisRegisterForEventHandler, reg);
  8362. }
  8363. }
  8364. RegSlot FunctionBody::GetThisRegisterForEventHandler() const
  8365. {
  8366. return m_hasThisRegisterForEventHandler ? GetCountField(CounterFields::ThisRegisterForEventHandler) : Constants::NoRegister;
  8367. }
  8368. void FunctionBody::SetLocalClosureRegister(RegSlot reg)
  8369. {
  8370. if (reg == Constants::NoRegister)
  8371. {
  8372. m_hasLocalClosureRegister = false;
  8373. }
  8374. else
  8375. {
  8376. m_hasLocalClosureRegister = true;
  8377. SetCountField(CounterFields::LocalClosureRegister, reg);
  8378. }
  8379. }
  8380. void FunctionBody::MapAndSetLocalClosureRegister(RegSlot reg)
  8381. {
  8382. Assert(!m_hasLocalClosureRegister);
  8383. SetLocalClosureRegister(this->MapRegSlot(reg));
  8384. }
  8385. RegSlot FunctionBody::GetLocalClosureRegister() const
  8386. {
  8387. return m_hasLocalClosureRegister ? GetCountField(CounterFields::LocalClosureRegister) : Constants::NoRegister;
  8388. }
  8389. void FunctionBody::SetParamClosureRegister(RegSlot reg)
  8390. {
  8391. if (reg == Constants::NoRegister)
  8392. {
  8393. m_hasParamClosureRegister = false;
  8394. }
  8395. else
  8396. {
  8397. m_hasParamClosureRegister = true;
  8398. SetCountField(CounterFields::ParamClosureRegister, reg);
  8399. }
  8400. }
  8401. void FunctionBody::MapAndSetParamClosureRegister(RegSlot reg)
  8402. {
  8403. Assert(!m_hasParamClosureRegister);
  8404. SetParamClosureRegister(this->MapRegSlot(reg));
  8405. }
  8406. RegSlot FunctionBody::GetParamClosureRegister() const
  8407. {
  8408. return m_hasParamClosureRegister ? GetCountField(CounterFields::ParamClosureRegister) : Constants::NoRegister;
  8409. }
  8410. void FunctionBody::MapAndSetLocalFrameDisplayRegister(RegSlot reg)
  8411. {
  8412. Assert(!m_hasLocalFrameDisplayRegister);
  8413. SetLocalFrameDisplayRegister(this->MapRegSlot(reg));
  8414. }
  8415. void FunctionBody::SetLocalFrameDisplayRegister(RegSlot reg)
  8416. {
  8417. if (reg == Constants::NoRegister)
  8418. {
  8419. m_hasLocalFrameDisplayRegister = false;
  8420. }
  8421. else
  8422. {
  8423. m_hasLocalFrameDisplayRegister = true;
  8424. SetCountField(CounterFields::LocalFrameDisplayRegister, reg);
  8425. }
  8426. }
  8427. RegSlot FunctionBody::GetLocalFrameDisplayRegister() const
  8428. {
  8429. return m_hasLocalFrameDisplayRegister ? GetCountField(CounterFields::LocalFrameDisplayRegister) : Constants::NoRegister;
  8430. }
  8431. void FunctionBody::MapAndSetFirstInnerScopeRegister(RegSlot reg)
  8432. {
  8433. Assert(!m_hasFirstInnerScopeRegister);
  8434. SetFirstInnerScopeRegister(this->MapRegSlot(reg));
  8435. }
  8436. void FunctionBody::SetFirstInnerScopeRegister(RegSlot reg)
  8437. {
  8438. if (reg == Constants::NoRegister)
  8439. {
  8440. m_hasFirstInnerScopeRegister = false;
  8441. }
  8442. else
  8443. {
  8444. m_hasFirstInnerScopeRegister = true;
  8445. SetCountField(CounterFields::FirstInnerScopeRegister, reg);
  8446. }
  8447. }
  8448. RegSlot FunctionBody::GetFirstInnerScopeRegister() const
  8449. {
  8450. return m_hasFirstInnerScopeRegister ? GetCountField(CounterFields::FirstInnerScopeRegister) : Constants::NoRegister;
  8451. }
  8452. void FunctionBody::MapAndSetFuncExprScopeRegister(RegSlot reg)
  8453. {
  8454. Assert(!m_hasFuncExprScopeRegister);
  8455. SetFuncExprScopeRegister(this->MapRegSlot(reg));
  8456. }
  8457. void FunctionBody::SetFuncExprScopeRegister(RegSlot reg)
  8458. {
  8459. if (reg == Constants::NoRegister)
  8460. {
  8461. m_hasFuncExprScopeRegister = false;
  8462. }
  8463. else
  8464. {
  8465. m_hasFuncExprScopeRegister = true;
  8466. SetCountField(CounterFields::FuncExprScopeRegister, reg);
  8467. }
  8468. }
  8469. RegSlot FunctionBody::GetFuncExprScopeRegister() const
  8470. {
  8471. return m_hasFuncExprScopeRegister ? GetCountField(CounterFields::FuncExprScopeRegister) : Constants::NoRegister;
  8472. }
  8473. void FunctionBody::SetFirstTmpRegister(RegSlot reg)
  8474. {
  8475. if (reg == Constants::NoRegister)
  8476. {
  8477. m_hasFirstTmpRegister = false;
  8478. }
  8479. else
  8480. {
  8481. m_hasFirstTmpRegister = true;
  8482. SetCountField(CounterFields::FirstTmpRegister, reg);
  8483. }
  8484. }
  8485. RegSlot FunctionBody::GetFirstTmpRegister() const
  8486. {
  8487. return m_hasFirstTmpRegister ? this->GetCountField(CounterFields::FirstTmpRegister) : Constants::NoRegister;
  8488. }
  8489. #if DBG && defined(ENABLE_SCRIPT_DEBUGGING)
  8490. Js::DebuggerMode FunctionBody::GetDebuggerMode()
  8491. {
  8492. return this->GetScriptContext()->GetDebugContext()->GetDebuggerMode();
  8493. }
  8494. #endif
  8495. }
  8496. #if !DBG
  8497. // Don't grow these data structure unless absolutely necessary
  8498. CompileAssert(sizeof(Js::EntryPointInfo) <= 56);
  8499. CompileAssert(sizeof(Js::FunctionEntryPointInfo) <= 96);
  8500. #endif