FunctionBody.cpp 350 KB

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