InterpreterStackFrame.cpp 312 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091
  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 "RuntimeLanguagePch.h"
  6. #include "EHBailoutData.h"
  7. #include "Library\JavascriptRegularExpression.h"
  8. #if DBG_DUMP
  9. #include "ByteCode\OpCodeUtilAsmJs.h"
  10. #endif
  11. #include "Language\InterpreterStackFrame.h"
  12. #include "Library\JavascriptGeneratorFunction.h"
  13. ///----------------------------------------------------------------------------
  14. ///
  15. /// macros PROCESS_INtoOUT
  16. ///
  17. /// This set of macros defines standard patterns for processing OpCodes in
  18. /// RcInterpreter::Run(). Each macro is named for "in" - "out":
  19. /// - A: Var
  20. /// - I: Integer
  21. /// - R: Double
  22. /// - X: Nothing
  23. ///
  24. /// Examples:
  25. /// - "A2toA1" reads two registers, each storing an Var, and writes a single
  26. /// register with a new Var.
  27. /// - "A1I1toA2" reads two registers, first an Var and second an Int32, then
  28. /// writes two Var registers.
  29. ///
  30. /// Although these could use lookup tables to standard OpLayout types, this
  31. /// additional indirection would slow the main interpreter loop further by
  32. /// preventing the main 'switch' statement from using the OpCode to become a
  33. /// direct local-function jump.
  34. ///----------------------------------------------------------------------------
  35. #define PROCESS_FALLTHROUGH(name, func) \
  36. case OpCode::name:
  37. #define PROCESS_FALLTHROUGH_COMMON(name, func, suffix) \
  38. case OpCode::name:
  39. #define PROCESS_READ_LAYOUT(name, layout, suffix) \
  40. CompileAssert(OpCodeInfo<OpCode::name>::Layout == OpLayoutType::layout); \
  41. const unaligned OpLayout##layout##suffix * playout = m_reader.layout##suffix(ip); \
  42. Assert((playout != nullptr) == (Js::OpLayoutType::##layout != Js::OpLayoutType::Empty)); // Make sure playout is used
  43. #define PROCESS_NOP_COMMON(name, layout, suffix) \
  44. case OpCode::name: \
  45. { \
  46. PROCESS_READ_LAYOUT(name, layout, suffix); \
  47. break; \
  48. }
  49. #define PROCESS_NOP(name, layout) PROCESS_NOP_COMMON(name, layout,)
  50. #define PROCESS_CUSTOM_COMMON(name, func, layout, suffix) \
  51. case OpCode::name: \
  52. { \
  53. PROCESS_READ_LAYOUT(name, layout, suffix); \
  54. func(playout); \
  55. break; \
  56. }
  57. #define PROCESS_CUSTOM(name, func, layout) PROCESS_CUSTOM_COMMON(name, func, layout,)
  58. #define PROCESS_CUSTOM_L_COMMON(name, func, layout, regslot, suffix) \
  59. case OpCode::name: \
  60. { \
  61. PROCESS_READ_LAYOUT(name, layout, suffix); \
  62. func(playout); \
  63. break; \
  64. }
  65. #define PROCESS_CUSTOM_L(name, func, layout, regslot) PROCESS_CUSTOM_L_COMMON(name, func, layout, regslot,)
  66. #define PROCESS_CUSTOM_L_Arg_COMMON(name, func, suffix) PROCESS_CUSTOM_L_COMMON(name, func, Arg, Arg, suffix)
  67. #define PROCESS_CUSTOM_L_Arg2_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, Arg, suffix)
  68. #define PROCESS_CUSTOM_L_Arg(name, func) PROCESS_CUSTOM_L_COMMON(name, func, Arg, Arg,)
  69. #define PROCESS_CUSTOM_ArgNoSrc_COMMON(name, func, suffix) PROCESS_CUSTOM_COMMON(name, func, ArgNoSrc, suffix)
  70. #define PROCESS_CUSTOM_ArgNoSrc(name, func) PROCESS_CUSTOM_COMMON(name, func, ArgNoSrc,)
  71. #define PROCESS_CUSTOM_L_R0_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, R0, suffix)
  72. #define PROCESS_CUSTOM_L_R0(name, func, layout) PROCESS_CUSTOM_L_COMMON(name, func, layout, R0,)
  73. #define PROCESS_CUSTOM_L_Value_COMMON(name, func, layout, suffix) PROCESS_CUSTOM_L_COMMON(name, func, layout, Value, suffix)
  74. #define PROCESS_CUSTOM_L_Value(name, func, layout) PROCESS_CUSTOM_L_COMMON(name, func, layout, Value,)
  75. #define PROCESS_TRY(name, func) \
  76. case OpCode::name: \
  77. { \
  78. PROCESS_READ_LAYOUT(name, Br,); \
  79. func(playout); \
  80. ip = m_reader.GetIP(); \
  81. break; \
  82. }
  83. #define PROCESS_EMPTY(name, func) \
  84. case OpCode::name: \
  85. { \
  86. PROCESS_READ_LAYOUT(name, Empty, ); \
  87. func(); \
  88. ip = m_reader.GetIP(); \
  89. break; \
  90. }
  91. #define PROCESS_TRYBR2_COMMON(name, func, suffix) \
  92. case OpCode::name: \
  93. { \
  94. PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
  95. func((const byte*)(playout + 1), playout->RelativeJumpOffset, playout->R1, playout->R2); \
  96. ip = m_reader.GetIP(); \
  97. break; \
  98. }
  99. #define PROCESS_CALL_COMMON(name, func, layout, suffix) \
  100. case OpCode::name: \
  101. { \
  102. PROCESS_READ_LAYOUT(name, layout, suffix); \
  103. func(playout); \
  104. break; \
  105. }
  106. #define PROCESS_CALL(name, func, layout) PROCESS_CALL_COMMON(name, func, layout,)
  107. #define PROCESS_CALL_FLAGS_COMMON(name, func, layout, flags, suffix) \
  108. case OpCode::name: \
  109. { \
  110. PROCESS_READ_LAYOUT(name, layout, suffix); \
  111. func(playout, flags); \
  112. break; \
  113. }
  114. #define PROCESS_CALL_FLAGS(name, func, layout, regslot) PROCESS_CALL_FLAGS_COMMON(name, func, layout, regslot,)
  115. #define PROCESS_CALL_FLAGS_None_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_None, suffix)
  116. #define PROCESS_CALL_FLAGS_None(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_None,)
  117. #define PROCESS_CALL_FLAGS_Value_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_Value, suffix)
  118. #define PROCESS_CALL_FLAGS_Value(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_Value,)
  119. #define PROCESS_CALL_FLAGS_CallEval_COMMON(name, func, layout, suffix) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_ExtraArg, suffix)
  120. #define PROCESS_CALL_FLAGS_CallEval(name, func, layout) PROCESS_CALL_FLAGS_COMMON(name, func, layout, CallFlags_ExtraArg,)
  121. #define PROCESS_A1toXX_ALLOW_STACK_COMMON(name, func, suffix) \
  122. case OpCode::name: \
  123. { \
  124. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  125. func(GetRegAllowStackVar(playout->R0)); \
  126. break; \
  127. }
  128. #define PROCESS_A1toXX_COMMON(name, func, suffix) \
  129. case OpCode::name: \
  130. { \
  131. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  132. func(GetReg(playout->R0)); \
  133. break; \
  134. }
  135. #define PROCESS_A1toXX(name, func) PROCESS_A1toXX_COMMON(name, func,)
  136. #define PROCESS_A1toXXMem_COMMON(name, func, suffix) \
  137. case OpCode::name: \
  138. { \
  139. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  140. func(GetReg(playout->R0), GetScriptContext()); \
  141. break; \
  142. }
  143. #define PROCESS_A1toXXMem(name, func) PROCESS_A1toXXMem_COMMON(name, func,)
  144. #define PROCESS_A1toXXMemNonVar_COMMON(name, func, type, suffix) \
  145. case OpCode::name: \
  146. { \
  147. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  148. func((type)GetNonVarReg(playout->R0), GetScriptContext()); \
  149. break; \
  150. }
  151. #define PROCESS_A1toXXMemNonVar(name, func, type) PROCESS_A1toXXMemNonVar_COMMON(name, func, type,)
  152. #define PROCESS_XXtoA1_COMMON(name, func, suffix) \
  153. case OpCode::name: \
  154. { \
  155. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  156. SetReg(playout->R0, \
  157. func()); \
  158. break; \
  159. }
  160. #define PROCESS_XXtoA1(name, func) PROCESS_XXtoA1_COMMON(name, func,)
  161. #define PROCESS_XXtoA1NonVar_COMMON(name, func, suffix) \
  162. case OpCode::name: \
  163. { \
  164. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  165. SetNonVarReg(playout->R0, \
  166. func()); \
  167. break; \
  168. }
  169. #define PROCESS_XXtoA1NonVar(name, func) PROCESS_XXtoA1NonVar_COMMON(name, func,)
  170. #define PROCESS_XXtoA1Mem_COMMON(name, func, suffix) \
  171. case OpCode::name: \
  172. { \
  173. PROCESS_READ_LAYOUT(name, Reg1, suffix); \
  174. SetReg(playout->R0, \
  175. func(GetScriptContext())); \
  176. break; \
  177. }
  178. #define PROCESS_XXtoA1Mem(name, func) PROCESS_XXtoA1Mem_COMMON(name, func,)
  179. #define PROCESS_A1toA1_ALLOW_STACK_COMMON(name, func, suffix) \
  180. case OpCode::name: \
  181. { \
  182. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  183. SetRegAllowStackVar(playout->R0, \
  184. func(GetRegAllowStackVar(playout->R1))); \
  185. break; \
  186. }
  187. #define PROCESS_A1toA1_ALLOW_STACK(name, func) PROCESS_A1toA1_ALLOW_STACK_COMMON(name, func,)
  188. #define PROCESS_A1toA1_COMMON(name, func, suffix) \
  189. case OpCode::name: \
  190. { \
  191. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  192. SetReg(playout->R0, \
  193. func(GetReg(playout->R1))); \
  194. break; \
  195. }
  196. #define PROCESS_A1toA1(name, func) PROCESS_A1toA1_COMMON(name, func,)
  197. #define PROCESS_A1toA1Profiled_COMMON(name, func, suffix) \
  198. case OpCode::name: \
  199. { \
  200. PROCESS_READ_LAYOUT(name, ProfiledReg2, suffix); \
  201. SetReg(playout->R0, \
  202. func(GetReg(playout->R1), playout->profileId)); \
  203. break; \
  204. }
  205. #define PROCESS_A1toA1Profiled(name, func) PROCESS_A1toA1Profiled_COMMON(name, func,)
  206. #define PROCESS_A1toA1CallNoArg_COMMON(name, func, layout, suffix) \
  207. case OpCode::name: \
  208. { \
  209. PROCESS_READ_LAYOUT(name, layout, suffix); \
  210. SetReg(playout->R0, \
  211. func(playout)); \
  212. break; \
  213. }
  214. #define PROCESS_A1toA1CallNoArg(name, func, layout) PROCESS_A1toA1CallNoArg_COMMON(name, func, layout,)
  215. #define PROCESS_A1toA1Mem_COMMON(name, func, suffix) \
  216. case OpCode::name: \
  217. { \
  218. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  219. SetReg(playout->R0, \
  220. func(GetReg(playout->R1),GetScriptContext())); \
  221. break; \
  222. }
  223. #define PROCESS_A1toA1Mem(name, func) PROCESS_A1toA1Mem_COMMON(name, func,)
  224. #define PROCESS_A1toA1NonVar_COMMON(name, func, suffix) \
  225. case OpCode::name: \
  226. { \
  227. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  228. SetNonVarReg(playout->R0, \
  229. func(GetNonVarReg(playout->R1))); \
  230. break; \
  231. }
  232. #define PROCESS_A1toA1NonVar(name, func) PROCESS_A1toA1NonVar_COMMON(name, func,)
  233. #define PROCESS_A1toA1MemNonVar_COMMON(name, func, suffix) \
  234. case OpCode::name: \
  235. { \
  236. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  237. SetNonVarReg(playout->R0, \
  238. func(GetNonVarReg(playout->R1),GetScriptContext())); \
  239. break; \
  240. }
  241. #define PROCESS_A1toA1MemNonVar(name, func) PROCESS_A1toA1MemNonVar_COMMON(name, func,)
  242. #define PROCESS_INNERtoA1_COMMON(name, func, suffix) \
  243. case OpCode::name: \
  244. { \
  245. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  246. SetReg(playout->R0, InnerScopeFromIndex(playout->C1)); \
  247. break; \
  248. }
  249. #define PROCESS_INNERtoA1(name, fun) PROCESS_INNERtoA1_COMMON(name, func,)
  250. #define PROCESS_U1toINNERMemNonVar_COMMON(name, func, suffix) \
  251. case OpCode::name: \
  252. { \
  253. PROCESS_READ_LAYOUT(name, Unsigned1, suffix); \
  254. SetInnerScopeFromIndex(playout->C1, func(GetScriptContext())); \
  255. break; \
  256. }
  257. #define PROCESS_U1toINNERMemNonVar(name, func) PROCESS_U1toINNERMemNonVar_COMMON(name, func,)
  258. #define PROCESS_XXINNERtoA1MemNonVar_COMMON(name, func, suffix) \
  259. case OpCode::name: \
  260. { \
  261. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  262. SetNonVarReg(playout->R0, \
  263. func(InnerScopeFromIndex(playout->C1), GetScriptContext())); \
  264. break; \
  265. }
  266. #define PROCESS_XXINNERtoA1MemNonVar(name, func) PROCESS_XXINNERtoA1MemNonVar_COMMON(name, func,)
  267. #define PROCESS_A1INNERtoA1MemNonVar_COMMON(name, func, suffix) \
  268. case OpCode::name: \
  269. { \
  270. PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
  271. SetNonVarReg(playout->R0, \
  272. func(InnerScopeFromIndex(playout->C1), GetNonVarReg(playout->R1), GetScriptContext())); \
  273. break; \
  274. }
  275. #define PROCESS_A1LOCALtoA1MemNonVar(name, func) PROCESS_A1LOCALtoA1MemNonVar_COMMON(name, func,)
  276. #define PROCESS_LOCALI1toA1_COMMON(name, func, suffix) \
  277. case OpCode::name: \
  278. { \
  279. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  280. SetReg(playout->R0, \
  281. func(this->localClosure, playout->C1)); \
  282. break; \
  283. }
  284. #define PROCESS_LOCALI1toA1(name, func) PROCESS_LOCALI1toA1_COMMON(name, func,)
  285. #define PROCESS_A1I1toA1_COMMON(name, func, suffix) \
  286. case OpCode::name: \
  287. { \
  288. PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
  289. SetReg(playout->R0, \
  290. func(GetReg(playout->R1), playout->C1)); \
  291. break; \
  292. }
  293. #define PROCESS_A1I1toA1(name, func) PROCESS_A1I1toA1_COMMON(name, func,)
  294. #define PROCESS_A1I1toA1Mem_COMMON(name, func, suffix) \
  295. case OpCode::name: \
  296. { \
  297. PROCESS_READ_LAYOUT(name, Reg2Int1, suffix); \
  298. SetReg(playout->R0, \
  299. func(GetReg(playout->R1), playout->C1, GetScriptContext())); \
  300. break; \
  301. }
  302. #define PROCESS_A1I1toA1Mem(name, func) PROCESS_A1I1toA1Mem_COMMON(name, func,)
  303. #define PROCESS_RegextoA1_COMMON(name, func, suffix) \
  304. case OpCode::name: \
  305. { \
  306. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  307. SetReg(playout->R0, \
  308. func(this->m_functionBody->GetLiteralRegex(playout->C1), GetScriptContext())); \
  309. break; \
  310. }
  311. #define PROCESS_RegextoA1(name, func) PROCESS_RegextoA1_COMMON(name, func,)
  312. #define PROCESS_A2toXX_COMMON(name, func, suffix) \
  313. case OpCode::name: \
  314. { \
  315. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  316. func(GetReg(playout->R0), GetReg(playout->R1)); \
  317. break; \
  318. }
  319. #define PROCESS_A2toXX(name, func) PROCESS_A2toXX_COMMON(name, func,)
  320. #define PROCESS_A2toXXMemNonVar_COMMON(name, func, suffix) \
  321. case OpCode::name: \
  322. { \
  323. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  324. func(GetNonVarReg(playout->R0), GetNonVarReg(playout->R1), GetScriptContext()); \
  325. break; \
  326. }
  327. #define PROCESS_A2toXXMemNonVar(name, func) PROCESS_A2toXXMemNonVar_COMMON(name, func,)
  328. #define PROCESS_A1NonVarToA1_COMMON(name, func, suffix) \
  329. case OpCode::name: \
  330. { \
  331. PROCESS_READ_LAYOUT(name, Reg2, suffix); \
  332. SetReg(playout->R0, \
  333. func(GetNonVarReg(playout->R1))); \
  334. break; \
  335. }
  336. #define PROCESS_A2NonVarToA1Reg_COMMON(name, func, suffix) \
  337. case OpCode::name: \
  338. { \
  339. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  340. SetReg(playout->R0, \
  341. func(GetNonVarReg(playout->R1), playout->R2)); \
  342. break; \
  343. }
  344. #define PROCESS_A2toA1Mem_COMMON(name, func, suffix) \
  345. case OpCode::name: \
  346. { \
  347. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  348. SetReg(playout->R0, \
  349. func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext())); \
  350. break; \
  351. }
  352. #define PROCESS_A2toA1Mem(name, func) PROCESS_A2toA1Mem_COMMON(name, func,)
  353. #define PROCESS_A2toA1MemProfiled_COMMON(name, func, suffix) \
  354. case OpCode::name: \
  355. { \
  356. PROCESS_READ_LAYOUT(name, ProfiledReg3, suffix); \
  357. SetReg(playout->R0, \
  358. func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext(), playout->profileId)); \
  359. break; \
  360. }
  361. #define PROCESS_A2toA1MemProfiled(name, func) PROCESS_A2toA1MemProfiled_COMMON(name, func,)
  362. #define PROCESS_A2toA1NonVar_COMMON(name, func, suffix) \
  363. case OpCode::name: \
  364. { \
  365. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  366. SetNonVarReg(playout->R0, \
  367. func(GetNonVarReg(playout->R1), GetNonVarReg(playout->R2))); \
  368. break; \
  369. }
  370. #define PROCESS_A2toA1NonVar(name, func) PROCESS_A2toA1NonVar_COMMON(name, func,)
  371. #define PROCESS_A2toA1MemNonVar_COMMON(name, func, suffix) \
  372. case OpCode::name: \
  373. { \
  374. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  375. SetNonVarReg(playout->R0, \
  376. func(GetNonVarReg(playout->R1), GetNonVarReg(playout->R2),GetScriptContext())); \
  377. break; \
  378. }
  379. #define PROCESS_A2toA1MemNonVar(name, func) PROCESS_A2toA1MemNonVar_COMMON(name, func,)
  380. #define PROCESS_CMMem_COMMON(name, func, suffix) \
  381. case OpCode::name: \
  382. { \
  383. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  384. SetReg(playout->R0, \
  385. func(GetReg(playout->R1), GetReg(playout->R2), GetScriptContext()) ? JavascriptBoolean::OP_LdTrue(GetScriptContext()) : \
  386. JavascriptBoolean::OP_LdFalse(GetScriptContext())); \
  387. break; \
  388. }
  389. #define PROCESS_CMMem(name, func) PROCESS_CMMem_COMMON(name, func,)
  390. #define PROCESS_ELEM_RtU_to_XX_COMMON(name, func, suffix) \
  391. case OpCode::name: \
  392. { \
  393. PROCESS_READ_LAYOUT(name, ElementRootU, suffix); \
  394. func(playout->PropertyIdIndex); \
  395. break; \
  396. }
  397. #define PROCESS_ELEM_RtU_to_XX(name, func) PROCESS_ELEM_RtU_to_XX_COMMON(name, func,)
  398. #define PROCESS_ELEM_C2_to_XX_COMMON(name, func, suffix) \
  399. case OpCode::name: \
  400. { \
  401. PROCESS_READ_LAYOUT(name, ElementScopedC, suffix); \
  402. func(GetEnvForEvalCode(), playout->PropertyIdIndex, GetReg(playout->Value)); \
  403. break; \
  404. }
  405. #define PROCESS_ELEM_C2_to_XX(name, func) PROCESS_ELEM_C2_to_XX_COMMON(name, func,)
  406. #define PROCESS_GET_ELEM_SLOT_FB_COMMON(name, func, suffix) \
  407. case OpCode::name: \
  408. { \
  409. PROCESS_READ_LAYOUT(name, ElementSlot, suffix); \
  410. SetReg(playout->Value, \
  411. func((FrameDisplay*)GetNonVarReg(playout->Instance), reinterpret_cast<Js::FunctionProxy**>(this->m_functionBody->GetNestedFuncReference(playout->SlotIndex)))); \
  412. break; \
  413. }
  414. #define PROCESS_GET_ELEM_SLOT_FB(name, func) PROCESS_GET_ELEM_SLOT_FB_COMMON(name, func,)
  415. #define PROCESS_GET_SLOT_FB_COMMON(name, func, suffix) \
  416. case OpCode::name: \
  417. { \
  418. PROCESS_READ_LAYOUT(name, ElementSlotI1, suffix); \
  419. SetReg(playout->Value, \
  420. func(this->GetFrameDisplayForNestedFunc(), reinterpret_cast<Js::FunctionProxy**>(this->m_functionBody->GetNestedFuncReference(playout->SlotIndex)))); \
  421. break; \
  422. }
  423. #define PROCESS_GET_SLOT_FB(name, func) PROCESS_GET_SLOT_FB_COMMON(name, func,)
  424. #define PROCESS_GET_ELEM_IMem_COMMON(name, func, suffix) \
  425. case OpCode::name: \
  426. { \
  427. PROCESS_READ_LAYOUT(name, ElementI, suffix); \
  428. SetReg(playout->Value, \
  429. func(GetReg(playout->Instance), GetReg(playout->Element), GetScriptContext())); \
  430. break; \
  431. }
  432. #define PROCESS_GET_ELEM_IMem(name, func) PROCESS_GET_ELEM_IMem_COMMON(name, func,)
  433. #define PROCESS_GET_ELEM_IMem_Strict_COMMON(name, func, suffix) \
  434. case OpCode::name: \
  435. { \
  436. PROCESS_READ_LAYOUT(name, ElementI, suffix); \
  437. SetReg(playout->Value, \
  438. func(GetReg(playout->Instance), GetReg(playout->Element), GetScriptContext(), PropertyOperation_StrictMode)); \
  439. break; \
  440. }
  441. #define PROCESS_GET_ELEM_IMem_Strict(name, func) PROCESS_GET_ELEM_IMem_Strict_COMMON(name, func,)
  442. #define PROCESS_BR(name, func) \
  443. case OpCode::name: \
  444. { \
  445. PROCESS_READ_LAYOUT(name, Br,); \
  446. ip = func(playout); \
  447. break; \
  448. }
  449. #ifdef BYTECODE_BRANCH_ISLAND
  450. #define PROCESS_BRLONG(name, func) \
  451. case OpCode::name: \
  452. { \
  453. PROCESS_READ_LAYOUT(name, BrLong,); \
  454. ip = func(playout); \
  455. break; \
  456. }
  457. #endif
  458. #define PROCESS_BRS(name,func) \
  459. case OpCode::name: \
  460. { \
  461. PROCESS_READ_LAYOUT(name, BrS,); \
  462. if (func(playout->val,GetScriptContext())) \
  463. { \
  464. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  465. } \
  466. break; \
  467. }
  468. #define PROCESS_BRB_COMMON(name, func, suffix) \
  469. case OpCode::name: \
  470. { \
  471. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  472. if (func(GetReg(playout->R1))) \
  473. { \
  474. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  475. } \
  476. break; \
  477. }
  478. #define PROCESS_BRB(name, func) PROCESS_BRB_COMMON(name, func,)
  479. #define PROCESS_BRB_ALLOW_STACK_COMMON(name, func, suffix) \
  480. case OpCode::name: \
  481. { \
  482. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  483. if (func(GetRegAllowStackVar(playout->R1))) \
  484. { \
  485. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  486. } \
  487. break; \
  488. }
  489. #define PROCESS_BRB_ALLOW_STACK(name, func) PROCESS_BRB_ALLOW_STACK_COMMON(name, func,)
  490. #define PROCESS_BRBS_COMMON(name, func, suffix) \
  491. case OpCode::name: \
  492. { \
  493. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  494. if (func(GetReg(playout->R1), GetScriptContext())) \
  495. { \
  496. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  497. } \
  498. break; \
  499. }
  500. #define PROCESS_BRBS(name, func) PROCESS_BRBS_COMMON(name, func,)
  501. #define PROCESS_BRBReturnP1toA1_COMMON(name, func, type, suffix) \
  502. case OpCode::name: \
  503. { \
  504. PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
  505. SetReg(playout->R1, func((type)GetNonVarReg(playout->R2))); \
  506. if (!GetReg(playout->R1)) \
  507. { \
  508. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  509. } \
  510. break; \
  511. }
  512. #define PROCESS_BRBReturnP1toA1(name, func, type) PROCESS_BRBReturnP1toA1_COMMON(name, func, type,)
  513. #define PROCESS_BRBMem_ALLOW_STACK_COMMON(name, func, suffix) \
  514. case OpCode::name: \
  515. { \
  516. PROCESS_READ_LAYOUT(name, BrReg1, suffix); \
  517. if (func(GetRegAllowStackVar(playout->R1),GetScriptContext())) \
  518. { \
  519. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  520. } \
  521. break; \
  522. }
  523. #define PROCESS_BRBMem_ALLOW_STACK(name, func) PROCESS_BRBMem_ALLOW_STACK_COMMON(name, func,)
  524. #define PROCESS_BRCMem_COMMON(name, func,suffix) \
  525. case OpCode::name: \
  526. { \
  527. PROCESS_READ_LAYOUT(name, BrReg2, suffix); \
  528. if (func(GetReg(playout->R1), GetReg(playout->R2),GetScriptContext())) \
  529. { \
  530. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  531. } \
  532. break; \
  533. }
  534. #define PROCESS_BRCMem(name, func) PROCESS_BRCMem_COMMON(name, func,)
  535. #define PROCESS_BRPROP(name, func) \
  536. case OpCode::name: \
  537. { \
  538. PROCESS_READ_LAYOUT(name, BrProperty,); \
  539. if (func(GetReg(playout->Instance), playout->PropertyIdIndex, GetScriptContext())) \
  540. { \
  541. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  542. } \
  543. break; \
  544. }
  545. #define PROCESS_BRLOCALPROP(name, func) \
  546. case OpCode::name: \
  547. { \
  548. PROCESS_READ_LAYOUT(name, BrLocalProperty,); \
  549. if (func(this->localClosure, playout->PropertyIdIndex, GetScriptContext())) \
  550. { \
  551. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  552. } \
  553. break; \
  554. }
  555. #define PROCESS_BRENVPROP(name, func) \
  556. case OpCode::name: \
  557. { \
  558. PROCESS_READ_LAYOUT(name, BrEnvProperty,); \
  559. if (func(LdEnv(), playout->SlotIndex, playout->PropertyIdIndex, GetScriptContext())) \
  560. { \
  561. ip = m_reader.SetCurrentRelativeOffset(ip, playout->RelativeJumpOffset); \
  562. } \
  563. break; \
  564. }
  565. #define PROCESS_W1(name, func) \
  566. case OpCode::name: \
  567. { \
  568. PROCESS_READ_LAYOUT(name, W1,); \
  569. func(playout->C1, GetScriptContext()); \
  570. break; \
  571. }
  572. #define PROCESS_U1toA1_COMMON(name, func, suffix) \
  573. case OpCode::name: \
  574. { \
  575. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  576. SetReg(playout->R0, \
  577. func(playout->C1,GetScriptContext())); \
  578. break; \
  579. }
  580. #define PROCESS_U1toA1(name, func) PROCESS_U1toA1_COMMON(name, func,)
  581. #define PROCESS_U1toA1NonVar_COMMON(name, func, suffix) \
  582. case OpCode::name: \
  583. { \
  584. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  585. SetNonVarReg(playout->R0, \
  586. func(playout->C1)); \
  587. break; \
  588. }
  589. #define PROCESS_U1toA1NonVar(name, func) PROCESS_U1toA1NonVar_COMMON(name, func,)
  590. #define PROCESS_U1toA1NonVar_FuncBody_COMMON(name, func, suffix) \
  591. case OpCode::name: \
  592. { \
  593. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  594. SetNonVarReg(playout->R0, \
  595. func(playout->C1,GetScriptContext(), this->m_functionBody)); \
  596. break; \
  597. }
  598. #define PROCESS_U1toA1NonVar_FuncBody(name, func) PROCESS_U1toA1NonVar_FuncBody_COMMON(name, func,)
  599. #define PROCESS_A1I2toXXNonVar_FuncBody(name, func) PROCESS_A1I2toXXNonVar_FuncBody_COMMON(name, func,)
  600. #define PROCESS_A1I2toXXNonVar_FuncBody_COMMON(name, func, suffix) \
  601. case OpCode::name: \
  602. { \
  603. PROCESS_READ_LAYOUT(name, Reg3, suffix); \
  604. func(playout->R0, playout->R1, playout->R2, GetScriptContext(), this->m_functionBody); \
  605. break; \
  606. }
  607. #define PROCESS_A1U1toXX_COMMON(name, func, suffix) \
  608. case OpCode::name: \
  609. { \
  610. PROCESS_READ_LAYOUT(name, Reg1Unsigned1, suffix); \
  611. func(GetNonVarReg(playout->R0), playout->C1); \
  612. break; \
  613. }
  614. #define PROCESS_A1U1toXX(name, func) PROCESS_A1U1toXX_COMMON(name, func,)
  615. #define PROCESS_EnvU1toXX_COMMON(name, func, suffix) \
  616. case OpCode::name: \
  617. { \
  618. PROCESS_READ_LAYOUT(name, Unsigned1, suffix); \
  619. func(LdEnv(), playout->C1); \
  620. break; \
  621. }
  622. #define PROCESS_EnvU1toXX(name, func) PROCESS_EnvU1toXX_COMMON(name, func,)
  623. #define PROCESS_GET_ELEM_SLOTNonVar_COMMON(name, func, layout, suffix) \
  624. case OpCode::name: \
  625. { \
  626. PROCESS_READ_LAYOUT(name, layout, suffix); \
  627. SetNonVarReg(playout->Value, func(GetNonVarReg(playout->Instance), playout)); \
  628. break; \
  629. }
  630. #define PROCESS_GET_ELEM_SLOTNonVar(name, func, layout) PROCESS_GET_ELEM_SLOTNonVar_COMMON(name, func, layout,)
  631. #define PROCESS_GET_ELEM_LOCALSLOTNonVar_COMMON(name, func, layout, suffix) \
  632. case OpCode::name: \
  633. { \
  634. PROCESS_READ_LAYOUT(name, layout, suffix); \
  635. SetNonVarReg(playout->Value, func((Var*)GetLocalClosure(), playout)); \
  636. break; \
  637. }
  638. #define PROCESS_GET_ELEM_LOCALSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_LOCALSLOTNonVar_COMMON(name, func, layout,)
  639. #define PROCESS_GET_ELEM_INNERSLOTNonVar_COMMON(name, func, layout, suffix) \
  640. case OpCode::name: \
  641. { \
  642. PROCESS_READ_LAYOUT(name, layout, suffix); \
  643. SetNonVarReg(playout->Value, func(InnerScopeFromIndex(playout->SlotIndex1), playout)); \
  644. break; \
  645. }
  646. #define PROCESS_GET_ELEM_INNERSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_INNERSLOTNonVar_COMMON(name, func, layout,)
  647. #define PROCESS_GET_ELEM_ENVSLOTNonVar_COMMON(name, func, layout, suffix) \
  648. case OpCode::name: \
  649. { \
  650. PROCESS_READ_LAYOUT(name, layout, suffix); \
  651. SetNonVarReg(playout->Value, func(LdEnv(), playout)); \
  652. break; \
  653. }
  654. #define PROCESS_GET_ELEM_ENVSLOTNonVar(name, func, layout) PROCESS_GET_ELEM_ENVSLOTNonVar_COMMON(name, func, layout,)
  655. #define PROCESS_SET_ELEM_SLOTNonVar_COMMON(name, func, suffix) \
  656. case OpCode::name: \
  657. { \
  658. PROCESS_READ_LAYOUT(name, ElementSlot, suffix); \
  659. func(GetNonVarReg(playout->Instance), playout->SlotIndex, GetRegAllowStackVarEnableOnly(playout->Value)); \
  660. break; \
  661. }
  662. #define PROCESS_SET_ELEM_SLOTNonVar(name, func) PROCESS_SET_ELEM_SLOTNonVar_COMMON(name, func,)
  663. #define PROCESS_SET_ELEM_LOCALSLOTNonVar_COMMON(name, func, suffix) \
  664. case OpCode::name: \
  665. { \
  666. PROCESS_READ_LAYOUT(name, ElementSlotI1, suffix); \
  667. func((Var*)GetLocalClosure(), playout->SlotIndex, GetRegAllowStackVarEnableOnly(playout->Value)); \
  668. break; \
  669. }
  670. #define PROCESS_SET_ELEM_LOCALSLOTNonVar(name, func) PROCESS_SET_ELEM_LOCALSLOTNonVar_COMMON(name, func,)
  671. #define PROCESS_SET_ELEM_INNERSLOTNonVar_COMMON(name, func, suffix) \
  672. case OpCode::name: \
  673. { \
  674. PROCESS_READ_LAYOUT(name, ElementSlotI2, suffix); \
  675. func(InnerScopeFromIndex(playout->SlotIndex1), playout->SlotIndex2, GetRegAllowStackVarEnableOnly(playout->Value)); \
  676. break; \
  677. }
  678. #define PROCESS_SET_ELEM_INNERSLOTNonVar(name, func) PROCESS_SET_ELEM_INNERSLOTNonVar_COMMON(name, func,)
  679. #define PROCESS_SET_ELEM_ENVSLOTNonVar_COMMON(name, func, suffix) \
  680. case OpCode::name: \
  681. { \
  682. PROCESS_READ_LAYOUT(name, ElementSlotI2, suffix); \
  683. func(LdEnv(), playout->SlotIndex1, playout->SlotIndex2, GetRegAllowStackVarEnableOnly(playout->Value)); \
  684. break; \
  685. }
  686. #define PROCESS_SET_ELEM_ENVSLOTNonVar(name, func) PROCESS_SET_ELEM_ENVSLOTNonVar_COMMON(name, func,)
  687. /*---------------------------------------------------------------------------------------------- */
  688. #define PROCESS_A3toA1Mem_COMMON(name, func, suffix) \
  689. case OpCode::name: \
  690. { \
  691. PROCESS_READ_LAYOUT(name, Reg4, suffix); \
  692. SetReg(playout->R0, \
  693. func(GetReg(playout->R1), GetReg(playout->R2), GetReg(playout->R3), GetScriptContext())); \
  694. break; \
  695. }
  696. #define PROCESS_A3toA1Mem(name, func) PROCESS_A3toA1Mem_COMMON(name, func,)
  697. /*---------------------------------------------------------------------------------------------- */
  698. #define PROCESS_A2I1toA1Mem_COMMON(name, func, suffix) \
  699. case OpCode::name: \
  700. { \
  701. PROCESS_READ_LAYOUT(name, Reg3B1, suffix); \
  702. SetReg(playout->R0, \
  703. func(GetReg(playout->R1), GetReg(playout->R2), playout->B3, GetScriptContext())); \
  704. break; \
  705. }
  706. #define PROCESS_A2I1toA1Mem(name, func) PROCESS_A2I1toA1Mem_COMMON(name, func,)
  707. /*---------------------------------------------------------------------------------------------- */
  708. #define PROCESS_A2I1toXXMem_COMMON(name, func, suffix) \
  709. case OpCode::name: \
  710. { \
  711. PROCESS_READ_LAYOUT(name, Reg2B1, suffix); \
  712. func(GetReg(playout->R0), GetReg(playout->R1), playout->B2, scriptContext); \
  713. break; \
  714. }
  715. #define PROCESS_A2I1toXXMem(name, func) PROCESS_A2I1toXXMem_COMMON(name, func,)
  716. /*---------------------------------------------------------------------------------------------- */
  717. #define PROCESS_A3I1toXXMem_COMMON(name, func, suffix) \
  718. case OpCode::name: \
  719. { \
  720. PROCESS_READ_LAYOUT(name, Reg3B1, suffix); \
  721. func(GetReg(playout->R0), GetReg(playout->R1), GetReg(playout->R2), playout->B3, scriptContext); \
  722. break; \
  723. }
  724. #define PROCESS_A3I1toXXMem(name, func) PROCESS_A3I1toXXMem_COMMON(name, func,)
  725. #if ENABLE_PROFILE_INFO
  726. #define PROCESS_IP_TARG_IMPL(name, func, layoutSize) \
  727. case OpCode::name: \
  728. { \
  729. Assert(!switchProfileMode); \
  730. ip = func<layoutSize, INTERPRETERPROFILE>(ip); \
  731. if(switchProfileMode) \
  732. { \
  733. m_reader.SetIP(ip); \
  734. return nullptr; \
  735. } \
  736. break; \
  737. }
  738. #else
  739. #define PROCESS_IP_TARG_IMPL(name, func, layoutSize) \
  740. case OpCode::name: \
  741. { \
  742. ip = func<layoutSize, INTERPRETERPROFILE>(ip); \
  743. break; \
  744. }
  745. #endif
  746. #define PROCESS_IP_TARG_COMMON(name, func, suffix) PROCESS_IP_TARG##suffix(name, func)
  747. #define PROCESS_IP_TARG_Large(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::LargeLayout)
  748. #define PROCESS_IP_TARG_Medium(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::MediumLayout)
  749. #define PROCESS_IP_TARG_Small(name, func) PROCESS_IP_TARG_IMPL(name, func, Js::SmallLayout)
  750. namespace Js
  751. {
  752. extern const __declspec(selectany) uint32 TypedArrayViewMask[] =
  753. {
  754. (uint32)~0 //TYPE_INT8
  755. , (uint32)~0 //TYPE_UINT8
  756. , (uint32)~1 //TYPE_INT16
  757. , (uint32)~1 //TYPE_UINT16
  758. , (uint32)~3 //TYPE_INT32
  759. , (uint32)~3 //TYPE_UINT32
  760. , (uint32)~3 //TYPE_FLOAT32
  761. , (uint32)~7 //TYPE_FLOAT64
  762. };
  763. #ifndef TEMP_DISABLE_ASMJS
  764. typedef void(InterpreterStackFrame::*ArrFunc)(uint32, RegSlot);
  765. const ArrFunc InterpreterStackFrame::StArrFunc[8] =
  766. {
  767. &InterpreterStackFrame::OP_StArr<int8>,
  768. &InterpreterStackFrame::OP_StArr<uint8>,
  769. &InterpreterStackFrame::OP_StArr<int16>,
  770. &InterpreterStackFrame::OP_StArr<uint16>,
  771. &InterpreterStackFrame::OP_StArr<int32>,
  772. &InterpreterStackFrame::OP_StArr<uint32>,
  773. &InterpreterStackFrame::OP_StArr<float>,
  774. &InterpreterStackFrame::OP_StArr<double>,
  775. };
  776. const ArrFunc InterpreterStackFrame::LdArrFunc[8] =
  777. {
  778. &InterpreterStackFrame::OP_LdArr<int8>,
  779. &InterpreterStackFrame::OP_LdArr<uint8>,
  780. &InterpreterStackFrame::OP_LdArr<int16>,
  781. &InterpreterStackFrame::OP_LdArr<uint16>,
  782. &InterpreterStackFrame::OP_LdArr<int32>,
  783. &InterpreterStackFrame::OP_LdArr<uint32>,
  784. &InterpreterStackFrame::OP_LdArr<float>,
  785. &InterpreterStackFrame::OP_LdArr<double>,
  786. };
  787. #endif
  788. Var InterpreterStackFrame::InnerScopeFromRegSlot(RegSlot reg) const
  789. {
  790. return InnerScopeFromIndex(reg - m_functionBody->FirstInnerScopeReg());
  791. }
  792. Var InterpreterStackFrame::InnerScopeFromIndex(uint32 index) const
  793. {
  794. if (index >= m_functionBody->GetInnerScopeCount())
  795. {
  796. AssertMsg(false, "Illegal byte code: bad inner scope index");
  797. Js::Throw::FatalInternalError();
  798. }
  799. Assert(this->innerScopeArray != nullptr);
  800. return this->innerScopeArray[index];
  801. }
  802. void InterpreterStackFrame::SetInnerScopeFromIndex(uint32 index, Var scope)
  803. {
  804. if (index >= m_functionBody->GetInnerScopeCount())
  805. {
  806. AssertMsg(false, "Illegal byte code: bad inner scope index");
  807. Js::Throw::FatalInternalError();
  808. }
  809. Assert(this->innerScopeArray != nullptr);
  810. this->innerScopeArray[index] = scope;
  811. }
  812. const int k_stackFrameVarCount = (sizeof(InterpreterStackFrame) + sizeof(Var) - 1) / sizeof(Var);
  813. InterpreterStackFrame::Setup::Setup(Js::ScriptFunction * function, Js::Arguments& args, bool inlinee)
  814. : function(function), inParams(args.Values), inSlotsCount(args.Info.Count), executeFunction(function->GetFunctionBody()), callFlags(args.Info.Flags), bailedOutOfInlinee(inlinee)
  815. {
  816. SetupInternal();
  817. }
  818. InterpreterStackFrame::Setup::Setup(Js::ScriptFunction * function, Var * inParams, int inSlotsCount, bool inlinee)
  819. : function(function), inParams(inParams), inSlotsCount(inSlotsCount), executeFunction(function->GetFunctionBody()), callFlags(CallFlags_None), bailedOutOfInlinee(inlinee)
  820. {
  821. SetupInternal();
  822. }
  823. void InterpreterStackFrame::Setup::SetupInternal()
  824. {
  825. if (this->function->GetHasInlineCaches() && Js::ScriptFunctionWithInlineCache::Is(this->function))
  826. {
  827. this->inlineCaches = Js::ScriptFunctionWithInlineCache::FromVar(this->function)->GetInlineCaches();
  828. }
  829. else
  830. {
  831. this->inlineCaches = this->executeFunction->GetInlineCaches();
  832. }
  833. this->inlineCacheCount = this->executeFunction->GetInlineCacheCount();
  834. //
  835. // Compute the amount of memory needed on the stack:
  836. // - We compute this in 'Atoms' instead of 'bytes' to keep everything natural word aligned.
  837. //
  838. this->localCount = this->executeFunction->GetLocalsCount();
  839. uint extraVarCount = 0;
  840. #if ENABLE_PROFILE_INFO
  841. if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
  842. {
  843. extraVarCount += (sizeof(ImplicitCallFlags) * this->executeFunction->GetLoopCount() + sizeof(Var) - 1) / sizeof(Var);
  844. }
  845. #endif
  846. this->varAllocCount = k_stackFrameVarCount + localCount + this->executeFunction->GetOutParamsDepth() + extraVarCount + this->executeFunction->GetInnerScopeCount();
  847. if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
  848. {
  849. // Track stack funcs...
  850. this->varAllocCount += (sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount()) / sizeof(Var);
  851. if (!this->bailedOutOfInlinee)
  852. {
  853. // Frame display (if environment depth is statically known)...
  854. if (this->executeFunction->DoStackFrameDisplay())
  855. {
  856. uint16 envDepth = this->executeFunction->GetEnvDepth();
  857. Assert(envDepth != (uint16)-1);
  858. this->varAllocCount += sizeof(FrameDisplay) / sizeof(Var) + (envDepth + 1);
  859. }
  860. // ...and scope slots (if any)
  861. if (this->executeFunction->DoStackScopeSlots())
  862. {
  863. uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
  864. Assert(scopeSlots != 0);
  865. this->varAllocCount += scopeSlots + Js::ScopeSlots::FirstSlotIndex;
  866. }
  867. }
  868. }
  869. }
  870. InterpreterStackFrame *
  871. InterpreterStackFrame::Setup::InitializeAllocation(__in_ecount(varAllocCount) Var * allocation, bool initParams, bool profileParams, Var loopHeaderArray, DWORD_PTR stackAddr
  872. #if DBG
  873. , Var invalidStackVar
  874. #endif
  875. )
  876. {
  877. //
  878. // Initialize the new InterpreterStackFrame instance on the program stack.
  879. //
  880. //This will fail if InterpreterStackFrame ever gets a non-empty ctor (you'll need to use
  881. //placement_new(allocation, InterpreterStackFrame) instead, though that will cause problems
  882. //if the placement_new is surrounded by a try/finally since this would mix C++/SEH exception
  883. //handling.
  884. __analysis_assume(varAllocCount >= k_stackFrameVarCount + localCount);
  885. InterpreterStackFrame* newInstance = (InterpreterStackFrame*)allocation;
  886. newInstance->scriptContext = this->executeFunction->GetScriptContext();
  887. newInstance->m_inSlotsCount = this->inSlotsCount;
  888. newInstance->m_inParams = this->inParams;
  889. newInstance->m_callFlags = this->callFlags;
  890. newInstance->m_outParams = newInstance->m_localSlots + localCount;
  891. newInstance->m_outSp = newInstance->m_outParams;
  892. newInstance->m_arguments = NULL;
  893. newInstance->function = this->function;
  894. newInstance->m_functionBody = this->executeFunction;
  895. newInstance->inlineCaches = this->inlineCaches;
  896. newInstance->inlineCacheCount = this->inlineCacheCount;
  897. newInstance->currentLoopNum = LoopHeader::NoLoop;
  898. newInstance->currentLoopCounter = 0;
  899. newInstance->m_flags = InterpreterStackFrameFlags_None;
  900. newInstance->closureInitDone = false;
  901. #if ENABLE_PROFILE_INFO
  902. newInstance->switchProfileMode = false;
  903. newInstance->isAutoProfiling = false;
  904. newInstance->switchProfileModeOnLoopEndNumber = 0u - 1;
  905. #endif
  906. newInstance->ehBailoutData = nullptr;
  907. newInstance->nestedTryDepth = -1;
  908. newInstance->nestedCatchDepth = -1;
  909. newInstance->nestedFinallyDepth = -1;
  910. newInstance->retOffset = 0;
  911. newInstance->localFrameDisplay = nullptr;
  912. newInstance->localClosure = nullptr;
  913. newInstance->innerScopeArray = nullptr;
  914. bool doInterruptProbe = newInstance->scriptContext->GetThreadContext()->DoInterruptProbe(this->executeFunction);
  915. #if ENABLE_NATIVE_CODEGEN
  916. bool doJITLoopBody =
  917. !this->executeFunction->GetScriptContext()->GetConfig()->IsNoNative() &&
  918. !(this->executeFunction->GetHasTry() && (PHASE_OFF((Js::JITLoopBodyInTryCatchPhase), this->executeFunction) || this->executeFunction->GetHasFinally())) &&
  919. (this->executeFunction->ForceJITLoopBody() || this->executeFunction->IsJitLoopBodyPhaseEnabled()) &&
  920. !this->executeFunction->GetScriptContext()->IsInDebugMode();
  921. #else
  922. const bool doJITLoopBody = false;
  923. #endif
  924. // Pick a version of the LoopBodyStart OpCode handlers that is hardcoded to do loop body JIT and
  925. // interrupt probes as needed.
  926. if (doInterruptProbe)
  927. {
  928. #if ENABLE_NATIVE_CODEGEN
  929. if (doJITLoopBody)
  930. {
  931. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<true, true>;
  932. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<true, true>;
  933. }
  934. else
  935. #endif
  936. {
  937. #if ENABLE_PROFILE_INFO
  938. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<true, false>;
  939. #endif
  940. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<true, false>;
  941. }
  942. }
  943. else
  944. {
  945. #if ENABLE_NATIVE_CODEGEN
  946. if (doJITLoopBody)
  947. {
  948. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<false, true>;
  949. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<false, true>;
  950. }
  951. else
  952. #endif
  953. {
  954. #if ENABLE_PROFILE_INFO
  955. newInstance->opProfiledLoopBodyStart = &InterpreterStackFrame::ProfiledLoopBodyStart<false, false>;
  956. #endif
  957. newInstance->opLoopBodyStart = &InterpreterStackFrame::LoopBodyStart<false, false>;
  958. }
  959. }
  960. newInstance->loopHeaderArray = loopHeaderArray;
  961. newInstance->m_stackAddress = stackAddr;
  962. #if ENABLE_PROFILE_INFO
  963. // the savedLoopImplicitCallFlags is allocated at the end of the out param array
  964. newInstance->savedLoopImplicitCallFlags = nullptr;
  965. #endif
  966. char * nextAllocBytes = (char *)(newInstance->m_outParams + this->executeFunction->GetOutParamsDepth());
  967. if (this->executeFunction->GetInnerScopeCount())
  968. {
  969. newInstance->innerScopeArray = (Var*)nextAllocBytes;
  970. nextAllocBytes += this->executeFunction->GetInnerScopeCount() * sizeof(Var);
  971. }
  972. if (this->executeFunction->DoStackNestedFunc() && this->executeFunction->GetNestedCount() != 0)
  973. {
  974. newInstance->InitializeStackFunctions((StackScriptFunction *)nextAllocBytes);
  975. nextAllocBytes = nextAllocBytes + sizeof(StackScriptFunction) * this->executeFunction->GetNestedCount();
  976. if (!this->bailedOutOfInlinee)
  977. {
  978. if (this->executeFunction->DoStackFrameDisplay())
  979. {
  980. uint16 envDepth = this->executeFunction->GetEnvDepth();
  981. Assert(envDepth != (uint16)-1);
  982. newInstance->localFrameDisplay = (FrameDisplay*)nextAllocBytes;
  983. nextAllocBytes += sizeof(FrameDisplay) + (envDepth + 1) * sizeof(Var);
  984. }
  985. if (this->executeFunction->DoStackScopeSlots())
  986. {
  987. uint32 scopeSlots = this->executeFunction->scopeSlotArraySize;
  988. Assert(scopeSlots != 0);
  989. newInstance->localClosure = nextAllocBytes;
  990. nextAllocBytes += (scopeSlots + ScopeSlots::FirstSlotIndex) * sizeof(Var);
  991. }
  992. }
  993. }
  994. #if ENABLE_PROFILE_INFO
  995. if (Js::DynamicProfileInfo::EnableImplicitCallFlags(this->executeFunction))
  996. {
  997. /*
  998. __analysis_assume(varAllocCount == (k_stackFrameVarCount + localCount + executeFunction->GetOutParamsDepth()
  999. + ((sizeof(ImplicitCallFlags) * executeFunction->GetLoopCount() + sizeof(Var) - 1) / sizeof(Var))));
  1000. */
  1001. newInstance->savedLoopImplicitCallFlags = (ImplicitCallFlags *)nextAllocBytes;
  1002. for (uint i = 0; i < this->executeFunction->GetLoopCount(); i++)
  1003. {
  1004. #pragma prefast(suppress:26015, "Above analysis assume doesn't work")
  1005. newInstance->savedLoopImplicitCallFlags[i] = ImplicitCall_None;
  1006. }
  1007. }
  1008. #endif
  1009. #if DBG
  1010. if (CONFIG_ISENABLED(InitializeInterpreterSlotsWithInvalidStackVarFlag))
  1011. {
  1012. // Fill the local slots with the invalid stack var so that we will crash deterministically if something goes wrong
  1013. for (uint i = 0; i < localCount; ++i)
  1014. {
  1015. newInstance->m_localSlots[i] = invalidStackVar;
  1016. }
  1017. }
  1018. else
  1019. {
  1020. memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount);
  1021. }
  1022. #else
  1023. if (newInstance->scriptContext->IsInDebugMode())
  1024. {
  1025. // In the debug mode zero out the local slot, so this could prevent locals being uninitialized in the case of setNextStatement.
  1026. memset(newInstance->m_localSlots, 0, sizeof(Js::Var) * localCount);
  1027. }
  1028. // Zero out only the return slot. This is not a user local, so the byte code will not initialize
  1029. // it to "undefined". And it's not an expression temp, so, for instance, a jitted loop body may expect
  1030. // it to be valid on entry to the loop, where "valid" means either a var or null.
  1031. newInstance->SetNonVarReg(0, NULL);
  1032. #endif
  1033. // Initialize the low end of the local slots from the constant table.
  1034. // Skip the slot for the return value register.
  1035. this->executeFunction->InitConstantSlots(&newInstance->m_localSlots[FunctionBody::FirstRegSlot]);
  1036. // Set local FD/SS pointers to null until after we've successfully probed the stack in the process loop.
  1037. // That way we avoid trying to box these structures before they've been initialized in the byte code.
  1038. if (this->executeFunction->DoStackFrameDisplay())
  1039. {
  1040. newInstance->SetNonVarReg(executeFunction->GetLocalFrameDisplayReg(), nullptr);
  1041. }
  1042. if (this->executeFunction->DoStackScopeSlots())
  1043. {
  1044. Assert(!executeFunction->HasScopeObject());
  1045. newInstance->SetNonVarReg(executeFunction->GetLocalClosureReg(), nullptr);
  1046. }
  1047. Var *prestDest = &newInstance->m_localSlots[this->executeFunction->GetConstantCount()];
  1048. if (initParams)
  1049. {
  1050. #if ENABLE_PROFILE_INFO
  1051. Assert(!this->executeFunction->NeedEnsureDynamicProfileInfo());
  1052. #endif
  1053. if (profileParams)
  1054. {
  1055. #if ENABLE_PROFILE_INFO
  1056. Assert(this->executeFunction->HasExecutionDynamicProfileInfo());
  1057. #endif
  1058. FunctionBody* functionBody = this->executeFunction;
  1059. InitializeParams(newInstance, [functionBody](Var param, ArgSlot index)
  1060. {
  1061. #if ENABLE_PROFILE_INFO
  1062. functionBody->GetDynamicProfileInfo()->RecordParameterInfo(functionBody, index - 1, param);
  1063. #endif
  1064. }, &prestDest);
  1065. }
  1066. else
  1067. {
  1068. InitializeParams(newInstance, [](Var param, ArgSlot index) {}, &prestDest);
  1069. }
  1070. }
  1071. if (this->executeFunction->GetHasRestParameter())
  1072. {
  1073. InitializeRestParam(newInstance, prestDest);
  1074. }
  1075. Js::RegSlot envReg = executeFunction->GetEnvReg();
  1076. if (envReg != Js::Constants::NoRegister && envReg < executeFunction->GetConstantCount())
  1077. {
  1078. Assert(this->executeFunction->GetThisRegForEventHandler() == Constants::NoRegister);
  1079. // The correct FD (possibly distinct from the one on the function) is passed in the constant table.
  1080. this->function->SetEnvironment((Js::FrameDisplay*)newInstance->GetNonVarReg(envReg));
  1081. }
  1082. return newInstance;
  1083. }
  1084. template <class Fn>
  1085. void InterpreterStackFrame::Setup::InitializeParams(InterpreterStackFrame * newInstance, Fn callback, Var **pprestDest)
  1086. {
  1087. ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
  1088. Assert(requiredInParamCount > 1);
  1089. if (this->inSlotsCount >= requiredInParamCount)
  1090. {
  1091. Var * pArg = &newInstance->m_localSlots[executeFunction->GetConstantCount()];
  1092. Var * paGivenSrc = this->inParams + 1;
  1093. ArgSlot paramIndex = 1;
  1094. do
  1095. {
  1096. Var src = *paGivenSrc++;
  1097. callback(src, paramIndex);
  1098. *pArg++ = src;
  1099. paramIndex++;
  1100. }
  1101. while (paramIndex < requiredInParamCount);
  1102. *pprestDest = pArg;
  1103. }
  1104. else
  1105. {
  1106. InitializeParamsAndUndef(newInstance, callback, pprestDest);
  1107. }
  1108. }
  1109. template <class Fn>
  1110. void InterpreterStackFrame::Setup::InitializeParamsAndUndef(InterpreterStackFrame * newInstance, Fn callback, Var **pprestDest)
  1111. {
  1112. Var * pArg = &newInstance->m_localSlots[executeFunction->GetConstantCount()];
  1113. Var * paGivenSrc = this->inParams + 1;
  1114. ArgSlot requiredInParamCount = executeFunction->GetInParamsCount();
  1115. ArgSlot paramIndex = 1;
  1116. while (paramIndex < this->inSlotsCount)
  1117. {
  1118. Var src = *paGivenSrc++;
  1119. callback(src, paramIndex);
  1120. *pArg++ = src;
  1121. paramIndex++;
  1122. }
  1123. Var varUndef = executeFunction->GetScriptContext()->GetLibrary()->GetUndefined();
  1124. do
  1125. {
  1126. callback(varUndef, paramIndex);
  1127. *pArg++ = varUndef;
  1128. paramIndex++;
  1129. }
  1130. while (paramIndex < requiredInParamCount);
  1131. *pprestDest = pArg;
  1132. }
  1133. void InterpreterStackFrame::Setup::InitializeRestParam(InterpreterStackFrame * newInstance, Var *dest)
  1134. {
  1135. Var *src = this->inParams + executeFunction->GetInParamsCount();
  1136. if (this->inSlotsCount > executeFunction->GetInParamsCount())
  1137. {
  1138. // Create the rest array and copy the args directly into the contiguous head segment.
  1139. int excess = this->inSlotsCount - executeFunction->GetInParamsCount();
  1140. *dest = JavascriptArray::OP_NewScArray(excess, executeFunction->GetScriptContext());
  1141. JavascriptArray *array = static_cast<JavascriptArray *>(*dest);
  1142. Var *elements = ((SparseArraySegment<Var>*)array->GetHead())->elements;
  1143. js_memcpy_s(elements, excess * sizeof(Var), src, excess * sizeof(Var));
  1144. }
  1145. else
  1146. {
  1147. // Rest is an empty array when there are no excess parameters.
  1148. *dest = JavascriptArray::OP_NewScArray(0, executeFunction->GetScriptContext());
  1149. }
  1150. }
  1151. FrameDisplay * InterpreterStackFrame::GetEnvForEvalCode()
  1152. {
  1153. FrameDisplay *pScope;
  1154. if (m_functionBody->GetIsStrictMode() && m_functionBody->GetIsGlobalFunc())
  1155. {
  1156. pScope = this->GetLocalFrameDisplay();
  1157. }
  1158. else
  1159. {
  1160. pScope = (FrameDisplay*)this->LdEnv();
  1161. }
  1162. return pScope;
  1163. }
  1164. void InterpreterStackFrame::InitializeClosures()
  1165. {
  1166. FunctionBody *executeFunction = this->function->GetFunctionBody();
  1167. Var environment;
  1168. RegSlot thisRegForEventHandler = executeFunction->GetThisRegForEventHandler();
  1169. if (thisRegForEventHandler != Constants::NoRegister)
  1170. {
  1171. Var varThis = OP_ArgIn0();
  1172. SetReg(thisRegForEventHandler, varThis);
  1173. environment = JavascriptOperators::OP_LdHandlerScope(varThis, GetScriptContext());
  1174. this->SetEnv((FrameDisplay*)environment);
  1175. }
  1176. else
  1177. {
  1178. environment = this->LdEnv();
  1179. }
  1180. RegSlot closureReg = executeFunction->GetLocalClosureReg();
  1181. if (closureReg != Js::Constants::NoRegister)
  1182. {
  1183. Assert(closureReg >= executeFunction->GetConstantCount());
  1184. if (executeFunction->HasScopeObject())
  1185. {
  1186. Js::RegSlot funcExprScopeReg = executeFunction->GetFuncExprScopeReg();
  1187. if (funcExprScopeReg != Constants::NoRegister)
  1188. {
  1189. // t0 = NewPseudoScope
  1190. // t1 = LdFrameDisplay t0 env
  1191. Var funcExprScope = JavascriptOperators::OP_NewPseudoScope(GetScriptContext());
  1192. SetReg(funcExprScopeReg, funcExprScope);
  1193. environment = OP_LdFrameDisplay(funcExprScope, environment, GetScriptContext());
  1194. }
  1195. this->NewScopeObject();
  1196. }
  1197. else
  1198. {
  1199. this->NewScopeSlots();
  1200. }
  1201. this->SetNonVarReg(closureReg, nullptr);
  1202. }
  1203. Js::RegSlot frameDisplayReg = executeFunction->GetLocalFrameDisplayReg();
  1204. if (frameDisplayReg != Js::Constants::NoRegister && closureReg != Js::Constants::NoRegister)
  1205. {
  1206. Assert(frameDisplayReg >= executeFunction->GetConstantCount());
  1207. void *argHead = this->GetLocalClosure();
  1208. this->SetLocalFrameDisplay(this->NewFrameDisplay(argHead, environment));
  1209. this->SetNonVarReg(frameDisplayReg, nullptr);
  1210. }
  1211. this->closureInitDone = true;
  1212. }
  1213. #ifdef _M_IX86
  1214. #ifndef TEMP_DISABLE_ASMJS
  1215. int InterpreterStackFrame::GetAsmJsArgSize(AsmJsCallStackLayout* stack)
  1216. {
  1217. JavascriptFunction * func = stack->functionObject;
  1218. AsmJsFunctionInfo* asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  1219. uint argSize = (uint)(asmInfo->GetArgByteSize());
  1220. argSize = ::Math::Align<int32>(argSize, 8);
  1221. // 2 * sizeof(Var) is for functionObject, and another push that DynamicInterpreterThunk does
  1222. return argSize + 2 * sizeof(Var);
  1223. }
  1224. int InterpreterStackFrame::GetDynamicRetType(AsmJsCallStackLayout* stack)
  1225. {
  1226. return GetRetType(stack->functionObject);
  1227. }
  1228. int InterpreterStackFrame::GetRetType(JavascriptFunction* func)
  1229. {
  1230. AsmJsFunctionInfo* asmInfo = func->GetFunctionBody()->GetAsmJsFunctionInfo();
  1231. return asmInfo->GetReturnType().which();
  1232. }
  1233. DWORD InterpreterStackFrame::GetAsmIntDbValOffSet(AsmJsCallStackLayout* stack)
  1234. {
  1235. JavascriptFunction * func = stack->functionObject;
  1236. ScriptContext* scriptContext = func->GetScriptContext();
  1237. return (DWORD)scriptContext + ScriptContext::GetAsmIntDbValOffset();
  1238. }
  1239. DWORD InterpreterStackFrame::GetAsmSimdValOffSet(AsmJsCallStackLayout* stack)
  1240. {
  1241. JavascriptFunction * func = stack->functionObject;
  1242. ScriptContext* scriptContext = func->GetScriptContext();
  1243. return (DWORD)scriptContext + ScriptContext::GetAsmSimdValOffset();
  1244. }
  1245. #ifdef ASMJS_PLAT
  1246. /*
  1247. AsmInterpreterThunk
  1248. -------------------
  1249. This is the entrypoint for all Asm Interpreter calls (external and internal)
  1250. TODO - Make this a dynamic Interpreter thunk to support ETW
  1251. Functionality:
  1252. 1) Prolog
  1253. 2) call AsmInterpreter passing the function object
  1254. 3) Get The return type
  1255. 4) Check for Double or Float return type
  1256. 5) If true then retrieve the value stored at a constant offset from the ScriptContext
  1257. 6) Get Argument Size for callee cleanup
  1258. 7) EpiLog
  1259. a) Retrieve the frame pointer
  1260. b) Store the return address in register (edx)
  1261. c) Clean the arguments based on the arguments size
  1262. d) push the return address back into the stack
  1263. */
  1264. __declspec(naked)
  1265. void InterpreterStackFrame::InterpreterAsmThunk(AsmJsCallStackLayout* layout)
  1266. {
  1267. enum {
  1268. Void = AsmJsRetType::Void,
  1269. Signed = AsmJsRetType::Signed,
  1270. Float = AsmJsRetType::Float,
  1271. Double = AsmJsRetType::Double,
  1272. Int32x4 = AsmJsRetType::Int32x4,
  1273. Float32x4 = AsmJsRetType::Float32x4,
  1274. Float64x2 = AsmJsRetType::Float64x2
  1275. };
  1276. //Prolog
  1277. __asm
  1278. {
  1279. //Prologue
  1280. push ebp;
  1281. mov ebp, esp;
  1282. push layout; // push stack layout
  1283. call InterpreterStackFrame::AsmJsInterpreter;
  1284. push eax; // push the return value into the stack
  1285. push layout;
  1286. call InterpreterStackFrame::GetDynamicRetType;
  1287. cmp eax, Void;
  1288. je end;
  1289. cmp eax, Signed;
  1290. je end;
  1291. cmp eax, Float;
  1292. jne skipFloat;
  1293. // float
  1294. push layout;
  1295. call InterpreterStackFrame::GetAsmIntDbValOffSet;
  1296. cvtsd2ss xmm0, [eax];
  1297. jmp end;
  1298. skipFloat:
  1299. cmp eax, Double;
  1300. jne skipDouble;
  1301. // double
  1302. push layout;
  1303. call InterpreterStackFrame::GetAsmIntDbValOffSet;
  1304. movsd xmm0, [eax];
  1305. jmp end;
  1306. skipDouble:
  1307. // simd value
  1308. push layout;
  1309. call InterpreterStackFrame::GetAsmSimdValOffSet;
  1310. movups xmm0, [eax];
  1311. end:
  1312. push layout;
  1313. call InterpreterStackFrame::GetAsmJsArgSize;
  1314. mov ecx, eax;
  1315. pop eax; // pop the return value from AsmJsInterpreter to eax
  1316. // Epilog, callee cleanup
  1317. mov esp, ebp;
  1318. pop ebp;
  1319. // we need to move stack around in order to do callee cleanup
  1320. // unfortunately, we don't really have enough registers to do this cleanly
  1321. //
  1322. // we are rearranging the stack from this:
  1323. // 0x14 caller push scriptArg1
  1324. // 0x10 caller push functionObject
  1325. // 0x0C DynamicInterpreterThunk return address
  1326. // 0x08 DynamicInterpreterThunk push ebp
  1327. // 0x04 DynamicInterpreterThunk push functionObject
  1328. // 0x00 InterpreterAsmThunk return address <- stack pointer
  1329. // to this:
  1330. // 0x14 DynamicInterpreterThunk return address
  1331. // 0x10 DynamicInterpreterThunk push ebp
  1332. // 0x0C InterpreterAsmThunk return address <- stack pointer
  1333. push eax; // save eax
  1334. mov eax, esp;
  1335. add eax, ecx;
  1336. add eax, 0xC; // eax will be our stack destination. we need to move backwards because memory might overlap
  1337. mov edx, [esp+0x10];
  1338. mov [eax], edx; // move the dynamic interpreter thunk return location
  1339. sub eax, 0x4;
  1340. mov edx, [esp+0xC];
  1341. mov [eax], edx; // move the dynamic interpreter thunk "push ebp" location
  1342. // skip "push functionObject"
  1343. sub eax, 0x4;
  1344. mov edx, [esp+0x4];
  1345. mov [eax], edx; // move the return location
  1346. pop eax;
  1347. add esp, ecx; // cleanup arguments
  1348. ret;
  1349. }
  1350. }
  1351. #endif
  1352. #endif
  1353. #endif
  1354. #if DYNAMIC_INTERPRETER_THUNK
  1355. #ifdef _M_IX86
  1356. __declspec(naked)
  1357. Var InterpreterStackFrame::DelayDynamicInterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1358. {
  1359. __asm
  1360. {
  1361. push ebp
  1362. mov ebp, esp
  1363. push [esp+8] // push function object
  1364. call InterpreterStackFrame::EnsureDynamicInterpreterThunk;
  1365. #ifdef _CONTROL_FLOW_GUARD
  1366. // verify that the call target is valid
  1367. push eax
  1368. mov ecx, eax
  1369. call[__guard_check_icall_fptr]
  1370. pop eax
  1371. #endif
  1372. pop ebp
  1373. jmp eax
  1374. }
  1375. }
  1376. #endif
  1377. #endif
  1378. #if ENABLE_PROFILE_INFO
  1379. JavascriptMethod InterpreterStackFrame::EnsureDynamicInterpreterThunk(Js::ScriptFunction * function)
  1380. {
  1381. #if DYNAMIC_INTERPRETER_THUNK
  1382. Assert(function);
  1383. Js::FunctionBody *functionBody = function->GetFunctionBody();
  1384. JavascriptMethod entrypoint = functionBody->EnsureDynamicInterpreterThunk(function->GetFunctionEntryPointInfo());
  1385. Assert(!IsDelayDynamicInterpreterThunk(functionBody->GetDirectEntryPoint(function->GetEntryPointInfo())));
  1386. if (function->GetEntryPoint() == InterpreterStackFrame::DelayDynamicInterpreterThunk)
  1387. {
  1388. // If we are not profiling, or the function object is not cross site, this is the direct entry point.
  1389. // Change the entry point on the object
  1390. Assert(functionBody->GetDirectEntryPoint(function->GetEntryPointInfo()) == entrypoint);
  1391. function->ChangeEntryPoint(function->GetEntryPointInfo(), entrypoint);
  1392. }
  1393. // Return the original entry point to be called
  1394. return entrypoint;
  1395. #else
  1396. return function->GetEntryPoint();
  1397. #endif
  1398. }
  1399. #endif
  1400. bool InterpreterStackFrame::IsDelayDynamicInterpreterThunk(void * entryPoint)
  1401. {
  1402. return
  1403. #if DYNAMIC_INTERPRETER_THUNK
  1404. #if _M_X64
  1405. entryPoint == InterpreterStackFrame::AsmJsDelayDynamicInterpreterThunk ||
  1406. #endif
  1407. entryPoint == InterpreterStackFrame::DelayDynamicInterpreterThunk;
  1408. #else
  1409. false;
  1410. #endif
  1411. }
  1412. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1413. __declspec(thread) int InterpreterThunkStackCountTracker::s_count = 0;
  1414. #endif
  1415. #if DYNAMIC_INTERPRETER_THUNK
  1416. Var InterpreterStackFrame::InterpreterThunk(JavascriptCallStackLayout* layout)
  1417. {
  1418. Js::ScriptFunction * function = Js::ScriptFunction::FromVar(layout->functionObject);
  1419. Js::ArgumentReader args(&layout->callInfo, layout->args);
  1420. void* localReturnAddress = _ReturnAddress();
  1421. void* localAddressOfReturnAddress = _AddressOfReturnAddress();
  1422. return InterpreterHelper(function, args, localReturnAddress, localAddressOfReturnAddress);
  1423. }
  1424. #else
  1425. #pragma optimize("", off)
  1426. Var InterpreterStackFrame::InterpreterThunk(RecyclableObject* function, CallInfo callInfo, ...)
  1427. {
  1428. ARGUMENTS(args, callInfo);
  1429. void* localReturnAddress = _ReturnAddress();
  1430. void* localAddressOfReturnAddress = _AddressOfReturnAddress();
  1431. Assert(ScriptFunction::Is(function));
  1432. return InterpreterHelper(ScriptFunction::FromVar(function), args, localReturnAddress, localAddressOfReturnAddress);
  1433. }
  1434. #pragma optimize("", on)
  1435. #endif
  1436. Var InterpreterStackFrame::InterpreterHelper(ScriptFunction* function, ArgumentReader args, void* returnAddress, void* addressOfReturnAddress, const bool isAsmJs)
  1437. {
  1438. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1439. // Support for simulating partially initialized interpreter stack frame.
  1440. InterpreterThunkStackCountTracker tracker;
  1441. if (CONFIG_ISENABLED(InjectPartiallyInitializedInterpreterFrameErrorFlag) &&
  1442. CONFIG_FLAG(InjectPartiallyInitializedInterpreterFrameError) == InterpreterThunkStackCountTracker::GetCount())
  1443. {
  1444. switch (CONFIG_FLAG(InjectPartiallyInitializedInterpreterFrameErrorType))
  1445. {
  1446. case 0:
  1447. DebugBreak();
  1448. break;
  1449. case 1:
  1450. Js::JavascriptError::MapAndThrowError(function->GetScriptContext(), VBSERR_InternalError);
  1451. break;
  1452. default:
  1453. DebugBreak();
  1454. }
  1455. }
  1456. #endif
  1457. ScriptContext* functionScriptContext = function->GetScriptContext();
  1458. ThreadContext * threadContext = functionScriptContext->GetThreadContext();
  1459. Assert(!threadContext->IsDisableImplicitException());
  1460. functionScriptContext->VerifyAlive(!function->IsExternal());
  1461. Assert(threadContext->IsScriptActive());
  1462. Assert(threadContext->IsInScript());
  1463. FunctionBody* executeFunction = JavascriptFunction::FromVar(function)->GetFunctionBody();
  1464. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1465. if (!isAsmJs && executeFunction->IsByteCodeDebugMode() != functionScriptContext->IsInDebugMode()) // debug mode mismatch
  1466. {
  1467. if (executeFunction->GetUtf8SourceInfo()->GetIsLibraryCode())
  1468. {
  1469. Assert(!executeFunction->IsByteCodeDebugMode()); // Library script byteCode is never in debug mode
  1470. }
  1471. else
  1472. {
  1473. Throw::FatalInternalError();
  1474. }
  1475. }
  1476. #endif
  1477. if (executeFunction->interpretedCount == 0)
  1478. {
  1479. executeFunction->TraceInterpreterExecutionMode();
  1480. }
  1481. class AutoRestore
  1482. {
  1483. private:
  1484. ThreadContext *const threadContext;
  1485. const uint8 savedLoopDepth;
  1486. public:
  1487. AutoRestore(ThreadContext *const threadContext, FunctionBody *const executeFunction)
  1488. : threadContext(threadContext),
  1489. savedLoopDepth(threadContext->LoopDepth())
  1490. {
  1491. if (savedLoopDepth != 0 && !executeFunction->GetIsAsmJsFunction())
  1492. {
  1493. executeFunction->SetWasCalledFromLoop();
  1494. }
  1495. }
  1496. ~AutoRestore()
  1497. {
  1498. threadContext->SetLoopDepth(savedLoopDepth);
  1499. }
  1500. } autoRestore(threadContext, executeFunction);
  1501. #if ENABLE_PROFILE_INFO
  1502. DynamicProfileInfo * dynamicProfileInfo = nullptr;
  1503. const bool doProfile = executeFunction->GetInterpreterExecutionMode(false) == ExecutionMode::ProfilingInterpreter ||
  1504. functionScriptContext->IsInDebugMode() && DynamicProfileInfo::IsEnabled(executeFunction);
  1505. if (doProfile)
  1506. {
  1507. #if !DYNAMIC_INTERPRETER_THUNK
  1508. executeFunction->EnsureDynamicProfileInfo();
  1509. #endif
  1510. dynamicProfileInfo = executeFunction->GetDynamicProfileInfo();
  1511. threadContext->ClearImplicitCallFlags();
  1512. }
  1513. #else
  1514. const bool doProfile = false;
  1515. #endif
  1516. executeFunction->interpretedCount++;
  1517. #ifdef BGJIT_STATS
  1518. functionScriptContext->interpretedCount++;
  1519. functionScriptContext->maxFuncInterpret = max(functionScriptContext->maxFuncInterpret, executeFunction->interpretedCount);
  1520. #endif
  1521. AssertMsg(!executeFunction->IsDeferredParseFunction(),
  1522. "Non-intrinsic functions must provide byte-code to execute");
  1523. bool fReleaseAlloc = false;
  1524. InterpreterStackFrame* newInstance = nullptr;
  1525. Var* allocation = nullptr;
  1526. if (!isAsmJs && executeFunction->IsGenerator())
  1527. {
  1528. // If the FunctionBody is a generator then this call is being made by one of the three
  1529. // generator resuming methods: next(), throw(), or return(). They all pass the generator
  1530. // object as the first of two arguments. The real user arguments are obtained from the
  1531. // generator object. The second argument is the ResumeYieldData which is only needed
  1532. // when resuming a generator and so it only used here if a frame already exists on the
  1533. // generator object.
  1534. AssertMsg(args.Info.Count == 2, "Generator ScriptFunctions should only be invoked by generator APIs with the pair of arguments they pass in -- the generator object and a ResumeYieldData pointer");
  1535. JavascriptGenerator* generator = JavascriptGenerator::FromVar(args[0]);
  1536. newInstance = generator->GetFrame();
  1537. if (newInstance != nullptr)
  1538. {
  1539. ResumeYieldData* resumeYieldData = static_cast<ResumeYieldData*>(args[1]);
  1540. newInstance->SetNonVarReg(executeFunction->GetYieldRegister(), resumeYieldData);
  1541. // The debugger relies on comparing stack addresses of frames to decide when a step_out is complete so
  1542. // give the InterpreterStackFrame a legit enough stack address to make this comparison work.
  1543. newInstance->m_stackAddress = reinterpret_cast<DWORD_PTR>(&generator);
  1544. }
  1545. else
  1546. {
  1547. //
  1548. // Allocate a new InterpreterStackFrame instance on the recycler heap.
  1549. // It will live with the JavascriptGenerator object.
  1550. //
  1551. Arguments generatorArgs = generator->GetArguments();
  1552. InterpreterStackFrame::Setup setup(function, generatorArgs);
  1553. size_t varAllocCount = setup.GetAllocationVarCount();
  1554. size_t varSizeInBytes = varAllocCount * sizeof(Var);
  1555. DWORD_PTR stackAddr = reinterpret_cast<DWORD_PTR>(&generator); // as mentioned above, use any stack address from this frame to ensure correct debugging functionality
  1556. Var loopHeaderArray = executeFunction->GetHasAllocatedLoopHeaders() ? executeFunction->GetLoopHeaderArrayPtr() : nullptr;
  1557. allocation = RecyclerNewPlus(functionScriptContext->GetRecycler(), varSizeInBytes, Var);
  1558. AnalysisAssert(allocation);
  1559. #if DBG
  1560. // Allocate invalidVar on GC instead of stack since this InterpreterStackFrame will out live the current real frame
  1561. Js::RecyclableObject* invalidVar = (Js::RecyclableObject*)RecyclerNewPlusLeaf(functionScriptContext->GetRecycler(), sizeof(Js::RecyclableObject), Var);
  1562. AnalysisAssert(invalidVar);
  1563. memset(invalidVar, 0xFE, sizeof(Js::RecyclableObject));
  1564. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr, invalidVar);
  1565. #else
  1566. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns(), doProfile, loopHeaderArray, stackAddr);
  1567. #endif
  1568. newInstance->m_reader.Create(executeFunction);
  1569. generator->SetFrame(newInstance);
  1570. }
  1571. }
  1572. else
  1573. {
  1574. InterpreterStackFrame::Setup setup(function, args);
  1575. size_t varAllocCount = setup.GetAllocationVarCount();
  1576. size_t varSizeInBytes = varAllocCount * sizeof(Var);
  1577. //
  1578. // Allocate a new InterpreterStackFrame instance on the interpreter's virtual stack.
  1579. //
  1580. DWORD_PTR stackAddr;
  1581. // If the locals area exceeds a certain limit, allocate it from a private arena rather than
  1582. // this frame. The current limit is based on an old assert on the number of locals we would allow here.
  1583. if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
  1584. {
  1585. ArenaAllocator *tmpAlloc = nullptr;
  1586. fReleaseAlloc = functionScriptContext->EnsureInterpreterArena(&tmpAlloc);
  1587. allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
  1588. stackAddr = reinterpret_cast<DWORD_PTR>(&allocation); // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
  1589. }
  1590. else
  1591. {
  1592. PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(functionScriptContext, Js::Constants::MinStackInterpreter + varSizeInBytes);
  1593. allocation = (Var*)_alloca(varSizeInBytes);
  1594. stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
  1595. }
  1596. /*
  1597. * If the function has any loop headers, we allocate an array for the loop headers wrappers, and
  1598. * reference the wrappers in the array. We then push the pointer to the array onto the stack itself.
  1599. * We do this so that while the function is being interpreted, we don't want the jitted loop
  1600. * bodies to be collected, even if the loop body isn't being executed. The loop body will
  1601. * get collected when the function has been JITted, and when the function exits the interpreter.
  1602. * The array contains nulls if the loop body isn't jitted (or hasn't been jitted yet) but
  1603. * it's cheaper to just copy them all into the recycler array rather than just the ones that
  1604. * have been jitted.
  1605. */
  1606. Var loopHeaderArray = nullptr;
  1607. if (executeFunction->GetHasAllocatedLoopHeaders())
  1608. {
  1609. // Loop header array is recycler allocated, so we push it on the stack
  1610. // When we scan the stack, we'll recognize it as a recycler allocated
  1611. // object, and mark it's contents and keep the individual loop header
  1612. // wrappers alive
  1613. loopHeaderArray = executeFunction->GetLoopHeaderArrayPtr();
  1614. }
  1615. #if DBG
  1616. Js::RecyclableObject * invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
  1617. memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
  1618. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr, invalidStackVar);
  1619. #else
  1620. newInstance = setup.InitializeAllocation(allocation, executeFunction->GetHasImplicitArgIns() && !isAsmJs, doProfile, loopHeaderArray, stackAddr);
  1621. #endif
  1622. newInstance->m_reader.Create(executeFunction);
  1623. }
  1624. //
  1625. // Execute the function's byte-code, returning the return-value:
  1626. // - Mark that the function is current executing and may not be modified.
  1627. //
  1628. executeFunction->BeginExecution();
  1629. Var aReturn = nullptr;
  1630. {
  1631. if (!isAsmJs && functionScriptContext->IsInDebugMode())
  1632. {
  1633. #if DYNAMIC_INTERPRETER_THUNK
  1634. PushPopFrameHelper pushPopFrameHelper(newInstance, returnAddress, addressOfReturnAddress);
  1635. aReturn = newInstance->DebugProcess();
  1636. #else
  1637. aReturn = newInstance->DebugProcessThunk(_ReturnAddress(), _AddressOfReturnAddress());
  1638. #endif
  1639. }
  1640. else
  1641. {
  1642. #if DYNAMIC_INTERPRETER_THUNK
  1643. PushPopFrameHelper pushPopFrameHelper(newInstance, returnAddress, addressOfReturnAddress);
  1644. aReturn = newInstance->Process();
  1645. #else
  1646. aReturn = newInstance->ProcessThunk(_ReturnAddress(), _AddressOfReturnAddress());
  1647. #endif
  1648. }
  1649. }
  1650. executeFunction->EndExecution();
  1651. if (fReleaseAlloc)
  1652. {
  1653. functionScriptContext->ReleaseInterpreterArena();
  1654. }
  1655. #if ENABLE_PROFILE_INFO
  1656. if (doProfile)
  1657. {
  1658. dynamicProfileInfo->RecordImplicitCallFlags(threadContext->GetImplicitCallFlags());
  1659. }
  1660. #endif
  1661. if (isAsmJs)
  1662. {
  1663. return newInstance;
  1664. }
  1665. return aReturn;
  1666. }
  1667. #ifndef TEMP_DISABLE_ASMJS
  1668. #if _M_IX86
  1669. int InterpreterStackFrame::AsmJsInterpreter(AsmJsCallStackLayout* stack)
  1670. {
  1671. ScriptFunction * function = (ScriptFunction*)stack->functionObject;
  1672. Var* paramsAddr = stack->args;
  1673. int flags = CallFlags_Value;
  1674. ArgSlot nbArgs = UInt16Math::Add(function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetArgCount(), 1);
  1675. CallInfo callInfo((CallFlags)flags, nbArgs);
  1676. ArgumentReader args(&callInfo, paramsAddr);
  1677. void* returnAddress = _ReturnAddress();
  1678. void* addressOfReturnAddress = _AddressOfReturnAddress();
  1679. #if ENABLE_PROFILE_INFO
  1680. function->GetFunctionBody()->EnsureDynamicProfileInfo();
  1681. #endif
  1682. InterpreterStackFrame* newInstance = (InterpreterStackFrame*)InterpreterHelper(function, args, returnAddress, addressOfReturnAddress, true);
  1683. //Handle return value
  1684. AsmJsRetType::Which retType = (AsmJsRetType::Which) GetRetType(function);
  1685. int retVal = 0;
  1686. switch (retType)
  1687. {
  1688. case AsmJsRetType::Int32x4:
  1689. case AsmJsRetType::Float32x4:
  1690. case AsmJsRetType::Float64x2:
  1691. if (function->GetScriptContext()->GetConfig()->IsSimdjsEnabled())
  1692. {
  1693. function->GetScriptContext()->retAsmSimdVal = newInstance->m_localSimdSlots[0];
  1694. break;
  1695. }
  1696. Assert(UNREACHED);
  1697. // double return
  1698. case AsmJsRetType::Double:
  1699. function->GetScriptContext()->retAsmIntDbVal = newInstance->m_localDoubleSlots[0];
  1700. break;
  1701. // float return
  1702. case AsmJsRetType::Float:
  1703. function->GetScriptContext()->retAsmIntDbVal = (double)newInstance->m_localFloatSlots[0];
  1704. break;
  1705. // signed or void return
  1706. case AsmJsRetType::Signed:
  1707. case AsmJsRetType::Void:
  1708. retVal = newInstance->m_localIntSlots[0];
  1709. break;
  1710. default:
  1711. Assume(false);
  1712. }
  1713. return retVal;
  1714. }
  1715. #elif _M_X64
  1716. typedef double(*AsmJsInterpreterDoubleEP)(AsmJsCallStackLayout*, void *);
  1717. typedef float(*AsmJsInterpreterFloatEP)(AsmJsCallStackLayout*, void *);
  1718. typedef int(*AsmJsInterpreterIntEP)(AsmJsCallStackLayout*, void *);
  1719. void * InterpreterStackFrame::GetAsmJsInterpreterEntryPoint(AsmJsCallStackLayout* stack)
  1720. {
  1721. JavascriptFunction * function = stack->functionObject;
  1722. void * entryPoint = nullptr;
  1723. switch (function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetReturnType().which())
  1724. {
  1725. case Js::AsmJsRetType::Double:
  1726. {
  1727. entryPoint = (AsmJsInterpreterDoubleEP)Js::InterpreterStackFrame::AsmJsInterpreter < double > ;
  1728. break;
  1729. }
  1730. case Js::AsmJsRetType::Float:
  1731. {
  1732. entryPoint = (AsmJsInterpreterFloatEP)Js::InterpreterStackFrame::AsmJsInterpreter < float > ;
  1733. break;
  1734. }
  1735. case Js::AsmJsRetType::Signed:
  1736. case Js::AsmJsRetType::Void:
  1737. {
  1738. entryPoint = (AsmJsInterpreterIntEP)Js::InterpreterStackFrame::AsmJsInterpreter < int > ;
  1739. break;
  1740. }
  1741. case Js::AsmJsRetType::Int32x4:
  1742. case Js::AsmJsRetType::Float32x4:
  1743. case Js::AsmJsRetType::Float64x2:
  1744. {
  1745. entryPoint = Js::InterpreterStackFrame::AsmJsInterpreterSimdJs;
  1746. break;
  1747. }
  1748. default:
  1749. Assume(UNREACHED);
  1750. }
  1751. return entryPoint;
  1752. }
  1753. template<>
  1754. int InterpreterStackFrame::GetAsmJsRetVal<int>(InterpreterStackFrame* instance)
  1755. {
  1756. return instance->m_localIntSlots[0];
  1757. }
  1758. template<>
  1759. double InterpreterStackFrame::GetAsmJsRetVal<double>(InterpreterStackFrame* instance)
  1760. {
  1761. return instance->m_localDoubleSlots[0];
  1762. }
  1763. template<>
  1764. float InterpreterStackFrame::GetAsmJsRetVal<float>(InterpreterStackFrame* instance)
  1765. {
  1766. return instance->m_localFloatSlots[0];
  1767. }
  1768. template<>
  1769. X86SIMDValue InterpreterStackFrame::GetAsmJsRetVal<X86SIMDValue>(InterpreterStackFrame* instance)
  1770. {
  1771. return X86SIMDValue::ToX86SIMDValue(instance->m_localSimdSlots[0]);
  1772. }
  1773. template<typename T>
  1774. T InterpreterStackFrame::AsmJsInterpreter(AsmJsCallStackLayout* layout)
  1775. {
  1776. Js::ScriptFunction * function = Js::ScriptFunction::FromVar(layout->functionObject);
  1777. int flags = CallFlags_Value;
  1778. ArgSlot nbArgs = UInt16Math::Add(function->GetFunctionBody()->GetAsmJsFunctionInfo()->GetArgCount(), 1);
  1779. CallInfo callInfo((CallFlags)flags, nbArgs);
  1780. ArgumentReader args(&callInfo, (Var*)layout->args);
  1781. void* returnAddress = _ReturnAddress();
  1782. void* addressOfReturnAddress = _AddressOfReturnAddress();
  1783. function->GetFunctionBody()->EnsureDynamicProfileInfo();
  1784. InterpreterStackFrame* newInstance = (InterpreterStackFrame*)InterpreterHelper(function, args, returnAddress, addressOfReturnAddress, true);
  1785. return GetAsmJsRetVal<T>(newInstance);
  1786. }
  1787. __m128 InterpreterStackFrame::AsmJsInterpreterSimdJs(AsmJsCallStackLayout* layout)
  1788. {
  1789. return AsmJsInterpreter<X86SIMDValue>(layout).m128_value;
  1790. }
  1791. #endif
  1792. #endif
  1793. ///----------------------------------------------------------------------------
  1794. ///
  1795. /// InterpreterStackFrame::SetOut()
  1796. ///
  1797. /// SetOut() change the Var value stored in the specified "out parameter"
  1798. /// register.
  1799. ///
  1800. ///----------------------------------------------------------------------------
  1801. inline void InterpreterStackFrame::SetOut(ArgSlot outRegisterID, Var aValue)
  1802. {
  1803. //
  1804. // The "out" parameter slots are located at the end of the local register range, counting
  1805. // forwards. This results in the "in" parameter slots being disjoint from the rest of the
  1806. // InterpreterStackFrame.
  1807. // ..., InterpreterStackFrame A, Locals A[], ..., Out A:0, Out A:1, Out A:2, ...
  1808. // | In B:0, In B:1, ..., InterpreterStackFrame B, Locals B[], ...
  1809. // (current 'this') |
  1810. // (new 'this' after call)
  1811. //
  1812. Assert(m_outParams + outRegisterID < m_outSp);
  1813. m_outParams[outRegisterID] = aValue;
  1814. }
  1815. inline void InterpreterStackFrame::SetOut(ArgSlot_OneByte outRegisterID, Var aValue)
  1816. {
  1817. Assert(m_outParams + outRegisterID < m_outSp);
  1818. m_outParams[outRegisterID] = aValue;
  1819. }
  1820. inline void InterpreterStackFrame::OP_SetOutAsmDb( RegSlot outRegisterID, double val )
  1821. {
  1822. Assert( m_outParams + outRegisterID < m_outSp );
  1823. m_outParams[outRegisterID] = JavascriptNumber::NewWithCheck( val, scriptContext );
  1824. }
  1825. inline void InterpreterStackFrame::OP_SetOutAsmInt( RegSlot outRegisterID, int val )
  1826. {
  1827. Assert( m_outParams + outRegisterID < m_outSp );
  1828. m_outParams[outRegisterID] = JavascriptNumber::ToVar( val, scriptContext );
  1829. }
  1830. inline void InterpreterStackFrame::OP_I_SetOutAsmFlt(RegSlot outRegisterID, float val)
  1831. {
  1832. Assert(m_outParams + outRegisterID < m_outSp);
  1833. *(float*)(&(m_outParams[outRegisterID])) = val;
  1834. }
  1835. inline void InterpreterStackFrame::OP_I_SetOutAsmInt(RegSlot outRegisterID, int val)
  1836. {
  1837. Assert(m_outParams + outRegisterID < m_outSp);
  1838. *(int*)(&(m_outParams[outRegisterID])) = val;
  1839. }
  1840. inline void InterpreterStackFrame::OP_I_SetOutAsmDb(RegSlot outRegisterID, double val)
  1841. {
  1842. Assert(m_outParams + outRegisterID < m_outSp);
  1843. *(double*)(&(m_outParams[outRegisterID])) = val;
  1844. }
  1845. inline void InterpreterStackFrame::OP_I_SetOutAsmSimd(RegSlot outRegisterID, AsmJsSIMDValue val)
  1846. {
  1847. Assert(m_outParams + outRegisterID < m_outSp);
  1848. *(AsmJsSIMDValue*)(&(m_outParams[outRegisterID])) = val;
  1849. }
  1850. inline void InterpreterStackFrame::PushOut(Var aValue)
  1851. {
  1852. *m_outSp++ = aValue;
  1853. }
  1854. inline void InterpreterStackFrame::PopOut(ArgSlot argCount)
  1855. {
  1856. m_outSp -= (argCount+1);
  1857. m_outParams = (Var*)*m_outSp;
  1858. AssertMsg(m_localSlots + this->m_functionBody->GetLocalsCount() <= m_outSp &&
  1859. m_outSp < (m_localSlots + this->m_functionBody->GetLocalsCount() + this->m_functionBody->GetOutParamsDepth()),
  1860. "out args Stack pointer not in range after Pop");
  1861. }
  1862. void InterpreterStackFrame::ResetOut()
  1863. {
  1864. //
  1865. // Reset the m_outParams and m_outSp
  1866. //
  1867. m_outParams = m_localSlots + this->m_functionBody->GetLocalsCount();
  1868. m_outSp = m_outParams;
  1869. }
  1870. __declspec(noinline)
  1871. Var InterpreterStackFrame::DebugProcessThunk(void* returnAddress, void* addressOfReturnAddress)
  1872. {
  1873. PushPopFrameHelper pushPopFrameHelper(this, returnAddress, addressOfReturnAddress);
  1874. return this->DebugProcess();
  1875. }
  1876. //
  1877. // Under debug mode allow the exception to be swallowed and execution to continue
  1878. // if the debugger has specified that behavior.
  1879. //
  1880. Var InterpreterStackFrame::DebugProcess()
  1881. {
  1882. Assert(this->returnAddress != nullptr);
  1883. while (true)
  1884. {
  1885. JavascriptExceptionObject *exception = nullptr;
  1886. try
  1887. {
  1888. return this->ProcessWithDebugging();
  1889. }
  1890. catch (JavascriptExceptionObject *exception_)
  1891. {
  1892. Assert(exception_);
  1893. exception = exception_;
  1894. }
  1895. if (exception)
  1896. {
  1897. bool skipException = false;
  1898. if (exception != scriptContext->GetThreadContext()->GetPendingSOErrorObject()
  1899. && exception != scriptContext->GetThreadContext()->GetPendingOOMErrorObject())
  1900. {
  1901. skipException = exception->IsDebuggerSkip();
  1902. }
  1903. if (skipException)
  1904. {
  1905. // If we are going to swallow the exception then advance to the beginning of the next user statement
  1906. if (exception->IsIgnoreAdvanceToNextStatement()
  1907. || this->scriptContext->GetDebugContext()->GetProbeContainer()->AdvanceToNextUserStatement(this->m_functionBody, &this->m_reader))
  1908. {
  1909. // We must fix up the return value to at least be undefined:
  1910. this->SetReg((RegSlot)0,this->scriptContext->GetLibrary()->GetUndefined());
  1911. // If we recover from the exception, there may be a chance the out pointers in the InterpreterStackframe are not in a proper state.
  1912. // Reset them to correct the stack.
  1913. ResetOut();
  1914. // If we can successfully advance then continuing processing
  1915. continue;
  1916. }
  1917. }
  1918. exception = exception->CloneIfStaticExceptionObject(scriptContext);
  1919. throw exception;
  1920. }
  1921. }
  1922. }
  1923. template<>
  1924. OpCode InterpreterStackFrame::ReadByteOp<OpCode>(const byte *& ip
  1925. #if DBG_DUMP
  1926. , bool isExtended /*= false*/
  1927. #endif
  1928. )
  1929. {
  1930. #if DBG || DBG_DUMP
  1931. //
  1932. // For debugging byte-code, store the current offset before the instruction is read:
  1933. // - We convert this to "void *" to encourage the debugger to always display in hex,
  1934. // which matches the displayed offsets used by ByteCodeDumper.
  1935. //
  1936. this->DEBUG_currentByteOffset = (void *) m_reader.GetCurrentOffset();
  1937. #endif
  1938. OpCode op = ByteCodeReader::ReadByteOp(ip);
  1939. #if DBG_DUMP
  1940. this->scriptContext->byteCodeHistogram[(int)op]++;
  1941. if (PHASE_TRACE(Js::InterpreterPhase, this->m_functionBody))
  1942. {
  1943. Output::Print(L"%d.%d:Executing %s at offset 0x%X\n", this->m_functionBody->GetSourceContextId(), this->m_functionBody->GetLocalFunctionId(), Js::OpCodeUtil::GetOpCodeName((Js::OpCode)(op+((int)isExtended<<8))), DEBUG_currentByteOffset);
  1944. }
  1945. #endif
  1946. return op;
  1947. }
  1948. #ifndef TEMP_DISABLE_ASMJS
  1949. template<>
  1950. OpCodeAsmJs InterpreterStackFrame::ReadByteOp<OpCodeAsmJs>(const byte *& ip
  1951. #if DBG_DUMP
  1952. , bool isExtended /*= false*/
  1953. #endif
  1954. )
  1955. {
  1956. #if DBG || DBG_DUMP
  1957. //
  1958. // For debugging byte-code, store the current offset before the instruction is read:
  1959. // - We convert this to "void *" to encourage the debugger to always display in hex,
  1960. // which matches the displayed offsets used by ByteCodeDumper.
  1961. //
  1962. this->DEBUG_currentByteOffset = (void *) m_reader.GetCurrentOffset();
  1963. #endif
  1964. OpCodeAsmJs op = (OpCodeAsmJs)ByteCodeReader::ReadByteOp(ip);
  1965. #if DBG_DUMP
  1966. if (PHASE_TRACE(Js::AsmjsInterpreterPhase, this->m_functionBody))
  1967. {
  1968. Output::Print(L"%d.%d:Executing %s at offset 0x%X\n", this->m_functionBody->GetSourceContextId(), this->m_functionBody->GetLocalFunctionId(), Js::OpCodeUtilAsmJs::GetOpCodeName((Js::OpCodeAsmJs)(op+((int)isExtended<<8))), DEBUG_currentByteOffset);
  1969. }
  1970. #endif
  1971. return op;
  1972. }
  1973. #endif
  1974. __declspec(noinline)
  1975. Var InterpreterStackFrame::ProcessThunk(void* address, void* addressOfReturnAddress)
  1976. {
  1977. PushPopFrameHelper pushPopFrameHelper(this, address, addressOfReturnAddress);
  1978. return this->Process();
  1979. }
  1980. template<> uint32 InterpreterStackFrame::LogSizeOf<uint8>(){return 0;}
  1981. template<> uint32 InterpreterStackFrame::LogSizeOf<int8>(){return 0;}
  1982. template<> uint32 InterpreterStackFrame::LogSizeOf<uint16>(){return 1;}
  1983. template<> uint32 InterpreterStackFrame::LogSizeOf<int16>(){return 1;}
  1984. template<> uint32 InterpreterStackFrame::LogSizeOf<uint32>(){return 2;}
  1985. template<> uint32 InterpreterStackFrame::LogSizeOf<int32>(){return 2;}
  1986. template<> uint32 InterpreterStackFrame::LogSizeOf<float>(){return 2;}
  1987. template<> uint32 InterpreterStackFrame::LogSizeOf<double>(){return 3;}
  1988. Var InterpreterStackFrame::ProcessAsmJsModule()
  1989. {
  1990. #ifdef ASMJS_PLAT
  1991. Js::FunctionBody* asmJsModuleFunctionBody = GetFunctionBody();
  1992. AsmJsModuleInfo* info = asmJsModuleFunctionBody->GetAsmJsModuleInfo();
  1993. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  1994. if (Configuration::Global.flags.ForceAsmJsLinkFail)
  1995. {
  1996. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Forcing link failure");
  1997. return this->ProcessLinkFailedAsmJsModule();
  1998. }
  1999. #endif
  2000. if( m_inSlotsCount != info->GetArgInCount() + 1 )
  2001. {
  2002. // Error reparse without asm.js
  2003. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Invalid module argument count");
  2004. return this->ProcessLinkFailedAsmJsModule();
  2005. }
  2006. const AsmJsModuleMemory& moduleMemory = info->GetModuleMemory();
  2007. Var* moduleMemoryPtr = RecyclerNewArray( scriptContext->GetRecycler(), Var, moduleMemory.mMemorySize );
  2008. Var* arrayBufferPtr = moduleMemoryPtr + moduleMemory.mArrayBufferOffset;
  2009. Assert(moduleMemory.mArrayBufferOffset == AsmJsModuleMemory::MemoryTableBeginOffset);
  2010. Var* stdLibPtr = moduleMemoryPtr + moduleMemory.mStdLibOffset;
  2011. int* localIntSlots = (int*)(moduleMemoryPtr + moduleMemory.mIntOffset);
  2012. float* localFloatSlots = (float*)(moduleMemoryPtr + moduleMemory.mFloatOffset);
  2013. double* localDoubleSlots = (double*)(moduleMemoryPtr + moduleMemory.mDoubleOffset);
  2014. Var* localFunctionImports = moduleMemoryPtr + moduleMemory.mFFIOffset ;
  2015. Var* localModuleFunctions = moduleMemoryPtr + moduleMemory.mFuncOffset ;
  2016. Var** localFunctionTables = (Var**)(moduleMemoryPtr + moduleMemory.mFuncPtrOffset) ;
  2017. AsmJsSIMDValue* localSimdSlots = nullptr;
  2018. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  2019. {
  2020. localSimdSlots = ((AsmJsSIMDValue*)moduleMemoryPtr) + moduleMemory.mSimdOffset; // simdOffset is in SIMDValues
  2021. }
  2022. #if 0
  2023. // Align SIMD regs to 128 bits.
  2024. // We only have space to align if there are any SIMD variables. Otherwise, leave unaligned.
  2025. if (info->GetSimdRegCount())
  2026. {
  2027. AssertMsg((moduleMemory.mMemorySize / SIMD_SLOTS_SPACE) - moduleMemory.mSimdOffset >= 1, "Not enough space in module memory to align SIMD vars");
  2028. localSimdSlots = (AsmJsSIMDValue*)::Math::Align<int>((int)localSimdSlots, sizeof(AsmJsSIMDValue));
  2029. }
  2030. #endif
  2031. ThreadContext* threadContext = this->scriptContext->GetThreadContext();
  2032. *stdLibPtr = (m_inSlotsCount > 1) ? m_inParams[1] : nullptr;
  2033. Var foreign = (m_inSlotsCount > 2) ? m_inParams[2] : nullptr;
  2034. *arrayBufferPtr = (m_inSlotsCount > 3) ? m_inParams[3] : nullptr;
  2035. //cache the current state of the disable implicit call flag
  2036. DisableImplicitFlags prevDisableImplicitFlags = threadContext->GetDisableImplicitFlags();
  2037. ImplicitCallFlags saveImplicitcallFlags = threadContext->GetImplicitCallFlags();
  2038. // Disable implicit calls to check if any of the VarImport or Function Import leads to implicit calls
  2039. threadContext->DisableImplicitCall();
  2040. threadContext->SetImplicitCallFlags(ImplicitCallFlags::ImplicitCall_None);
  2041. bool checkParamResult = ASMLink::CheckParams(this->scriptContext, info, *stdLibPtr, foreign, *arrayBufferPtr);
  2042. if (!checkParamResult)
  2043. {
  2044. // don't need to print, because checkParams will do it for us
  2045. goto linkFailure;
  2046. }
  2047. else if(this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2048. {
  2049. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Params have side effects");
  2050. return this->ProcessLinkFailedAsmJsModule();
  2051. }
  2052. // Initialize Variables
  2053. for (int i = 0; i < info->GetVarCount(); i++)
  2054. {
  2055. const auto& var = info->GetVar( i );
  2056. const AsmJsVarType type(var.type);
  2057. if(type.isInt() )
  2058. {
  2059. localIntSlots[var.location] = var.initialiser.intInit;
  2060. }
  2061. else if (type.isFloat())
  2062. {
  2063. localFloatSlots[var.location] = var.initialiser.floatInit;
  2064. }
  2065. else if (type.isDouble())
  2066. {
  2067. localDoubleSlots[var.location] = var.initialiser.doubleInit;
  2068. }
  2069. else if (scriptContext->GetConfig()->IsSimdjsEnabled() && type.isSIMD())
  2070. {
  2071. // e.g. var g = f4(0.0, 0.0, 0.0, 0.0);
  2072. localSimdSlots[var.location] = var.initialiser.simdInit;
  2073. }
  2074. else {
  2075. Assert(UNREACHED);
  2076. }
  2077. }
  2078. // Load constant variables
  2079. for( int i = 0; i < info->GetVarImportCount(); i++ )
  2080. {
  2081. const auto& import = info->GetVarImport( i );
  2082. const AsmJsVarType type(import.type);
  2083. // this might throw, but it would anyway in non-asm.js
  2084. Var value = JavascriptOperators::OP_GetProperty( foreign, import.field, scriptContext );
  2085. // check if there is implicit call and if there is implicit call then clear the disableimplicitcall flag
  2086. if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2087. {
  2088. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Accessing var import %s has side effects", this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2089. return this->ProcessLinkFailedAsmJsModule();
  2090. }
  2091. if (CONFIG_FLAG(AsmJsEdge))
  2092. {
  2093. // emscripten had a bug which caused this check to fail in some circumstances, so this check fails for some demos
  2094. if (!TaggedNumber::Is(value) && (!RecyclableObject::Is(value) || DynamicType::Is(RecyclableObject::FromVar(value)->GetTypeId())))
  2095. {
  2096. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Var import %s must be primitive", this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2097. goto linkFailure;
  2098. }
  2099. }
  2100. if(type.isInt() )
  2101. {
  2102. int val = JavascriptMath::ToInt32( value, scriptContext );
  2103. localIntSlots[import.location] = val;
  2104. }
  2105. else if (type.isFloat())
  2106. {
  2107. float val = (float)JavascriptConversion::ToNumber(value, scriptContext);
  2108. localFloatSlots[import.location] = val;
  2109. }
  2110. else if (type.isDouble())
  2111. {
  2112. double val = JavascriptConversion::ToNumber( value, scriptContext );
  2113. localDoubleSlots[import.location] = val;
  2114. }
  2115. else if (scriptContext->GetConfig()->IsSimdjsEnabled() && type.isSIMD())
  2116. {
  2117. // e.g. var g = f4(imports.v);
  2118. bool valid = false;
  2119. AsmJsSIMDValue val;
  2120. val.Zero();
  2121. switch (type.which())
  2122. {
  2123. case AsmJsVarType::Int32x4:
  2124. valid = JavascriptSIMDInt32x4::Is(value);
  2125. val = ((JavascriptSIMDInt32x4*)value)->GetValue();
  2126. break;
  2127. case AsmJsVarType::Float32x4:
  2128. valid = JavascriptSIMDFloat32x4::Is(value);
  2129. val = ((JavascriptSIMDFloat32x4*)value)->GetValue();
  2130. break;
  2131. case AsmJsVarType::Float64x2:
  2132. valid = JavascriptSIMDFloat64x2::Is(value);
  2133. val = ((JavascriptSIMDFloat64x2*)value)->GetValue();
  2134. break;
  2135. default:
  2136. Assert(UNREACHED);
  2137. };
  2138. if (!valid)
  2139. {
  2140. // link failure of SIMD values imports.
  2141. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Foreign var import %s is not SIMD type", this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2142. goto linkFailure;
  2143. }
  2144. localSimdSlots[import.location] = val;
  2145. }
  2146. // check for implicit call after converting to number
  2147. if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2148. {
  2149. // Runtime error
  2150. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Accessing var import %s has side effects", this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2151. return this->ProcessLinkFailedAsmJsModule();
  2152. }
  2153. }
  2154. // Load external functions
  2155. for( int i = 0; i < info->GetFunctionImportCount(); i++ )
  2156. {
  2157. const auto& import = info->GetFunctionImport( i );
  2158. // this might throw, but it would anyway in non-asm.js
  2159. Var importFunc = JavascriptOperators::OP_GetProperty( foreign, import.field, scriptContext );
  2160. // check if there is implicit call and if there is implicit call then clear the disableimplicitcall flag
  2161. if (this->CheckAndResetImplicitCall(prevDisableImplicitFlags, saveImplicitcallFlags))
  2162. {
  2163. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Accessing foreign function import %s has side effects", this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2164. return this->ProcessLinkFailedAsmJsModule();
  2165. }
  2166. if( !JavascriptFunction::Is( importFunc ) )
  2167. {
  2168. AsmJSCompiler::OutputError(this->scriptContext, L"Asm.js Runtime Error : Foreign function import %s is not a function", this->scriptContext->GetPropertyName(import.field)->GetBuffer());
  2169. goto linkFailure;
  2170. }
  2171. localFunctionImports[import.location] = importFunc;
  2172. }
  2173. if (*arrayBufferPtr)
  2174. {
  2175. (*(ArrayBuffer**)arrayBufferPtr)->SetIsAsmJsBuffer();
  2176. }
  2177. threadContext->SetDisableImplicitFlags(prevDisableImplicitFlags);
  2178. threadContext->SetImplicitCallFlags(saveImplicitcallFlags);
  2179. FrameDisplay* pDisplay = RecyclerNewPlus(scriptContext->GetRecycler(), sizeof(void*), FrameDisplay, 1);
  2180. pDisplay->SetItem( 0, moduleMemoryPtr );
  2181. for (int i = 0; i < info->GetFunctionCount(); i++)
  2182. {
  2183. const auto& modFunc = info->GetFunction(i);
  2184. // TODO: add more runtime checks here
  2185. auto proxy = m_functionBody->GetNestedFuncReference(i);
  2186. AsmJsScriptFunction* scriptFuncObj = (AsmJsScriptFunction*)ScriptFunction::OP_NewScFunc(pDisplay, (FunctionProxy**)proxy);
  2187. localModuleFunctions[modFunc.location] = scriptFuncObj;
  2188. if (i == 0 && info->GetUsesChangeHeap())
  2189. {
  2190. scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsChangeHeapBuffer);
  2191. }
  2192. else
  2193. {
  2194. if (scriptFuncObj->GetDynamicType()->GetEntryPoint() == DefaultDeferredDeserializeThunk)
  2195. {
  2196. JavascriptFunction::DeferredDeserialize(scriptFuncObj);
  2197. }
  2198. scriptFuncObj->GetDynamicType()->SetEntryPoint(AsmJsExternalEntryPoint);
  2199. scriptFuncObj->GetFunctionBody()->GetAsmJsFunctionInfo()->SetModuleFunctionBody(asmJsModuleFunctionBody);
  2200. }
  2201. scriptFuncObj->SetModuleMemory(moduleMemoryPtr);
  2202. if (!info->IsRuntimeProcessed())
  2203. {
  2204. // don't reset entrypoint upon relinking
  2205. FunctionEntryPointInfo* entypointInfo = (FunctionEntryPointInfo*)scriptFuncObj->GetEntryPointInfo();
  2206. entypointInfo->SetIsAsmJSFunction(true);
  2207. entypointInfo->SetModuleAddress((uintptr_t)moduleMemoryPtr);
  2208. #if DYNAMIC_INTERPRETER_THUNK
  2209. if (!PHASE_ON1(AsmJsJITTemplatePhase))
  2210. {
  2211. entypointInfo->address = AsmJsDefaultEntryThunk;
  2212. }
  2213. #endif
  2214. }
  2215. }
  2216. // Initialize function table arrays
  2217. for( int i = 0; i < info->GetFunctionTableCount(); i++ )
  2218. {
  2219. const auto& modFuncTable = info->GetFunctionTable( i );
  2220. Var* funcTableArray = RecyclerNewArray( scriptContext->GetRecycler(), Var, modFuncTable.size );
  2221. for (uint j = 0; j < modFuncTable.size ; j++)
  2222. {
  2223. // get the module function index
  2224. const RegSlot index = modFuncTable.moduleFunctionIndex[j];
  2225. // assign the module function pointer to the array
  2226. Var functionPtr = localModuleFunctions[index];
  2227. funcTableArray[j] = functionPtr;
  2228. }
  2229. localFunctionTables[i] = funcTableArray;
  2230. }
  2231. // Do MTJRC/MAIC:0 check
  2232. #if ENABLE_DEBUG_CONFIG_OPTIONS
  2233. if ((PHASE_ON1(Js::AsmJsJITTemplatePhase) && CONFIG_FLAG(MaxTemplatizedJitRunCount) == 0) || (!PHASE_ON1(Js::AsmJsJITTemplatePhase) && CONFIG_FLAG(MaxAsmJsInterpreterRunCount) == 0))
  2234. {
  2235. if (PHASE_TRACE1(AsmjsEntryPointInfoPhase))
  2236. {
  2237. Output::Print(L"%s Scheduling For Full JIT at callcount:%d\n", asmJsModuleFunctionBody->GetDisplayName(), 0);
  2238. Output::Flush();
  2239. }
  2240. for (int i = 0; i < info->GetFunctionCount(); i++)
  2241. {
  2242. ScriptFunction* functionObj = (ScriptFunction*)localModuleFunctions[i];
  2243. AnalysisAssert(functionObj != nullptr);
  2244. // don't want to generate code for APIs like changeHeap
  2245. if (functionObj->GetEntryPoint() == Js::AsmJsExternalEntryPoint)
  2246. {
  2247. GenerateFunction(asmJsModuleFunctionBody->GetScriptContext()->GetNativeCodeGenerator(), functionObj->GetFunctionBody(), functionObj);
  2248. }
  2249. }
  2250. }
  2251. #endif
  2252. info->SetIsRuntimeProcessed(true);
  2253. // create export object
  2254. if( info->GetExportsCount() )
  2255. {
  2256. Var newObj = JavascriptOperators::NewScObjectLiteral( GetScriptContext(), info->GetExportsIdArray(),
  2257. this->GetFunctionBody()->GetObjectLiteralTypeRef( 0 ) );
  2258. for( int i = 0; i < info->GetExportsCount(); i++ )
  2259. {
  2260. auto ex = info->GetExport( i );
  2261. Var func = localModuleFunctions[*ex.location];
  2262. JavascriptOperators::OP_InitProperty( newObj, *ex.id, func );
  2263. }
  2264. SetReg( (RegSlot) 0, newObj );
  2265. return newObj;
  2266. }
  2267. // export only 1 function
  2268. Var exportFunc = localModuleFunctions[info->GetExportFunctionIndex()];
  2269. SetReg((RegSlot)0, exportFunc);
  2270. return exportFunc;
  2271. linkFailure:
  2272. threadContext->SetDisableImplicitFlags(prevDisableImplicitFlags);
  2273. threadContext->SetImplicitCallFlags(saveImplicitcallFlags);
  2274. return this->ProcessLinkFailedAsmJsModule();
  2275. }
  2276. Var InterpreterStackFrame::ProcessLinkFailedAsmJsModule()
  2277. {
  2278. AsmJSCompiler::OutputError(this->scriptContext, L"asm.js linking failed.");
  2279. Js::FunctionBody* asmJsModuleFunctionBody = GetFunctionBody();
  2280. AsmJsModuleInfo* info = asmJsModuleFunctionBody->GetAsmJsModuleInfo();
  2281. // do not support relinking with failed relink
  2282. if (info->IsRuntimeProcessed())
  2283. {
  2284. Js::Throw::OutOfMemory();
  2285. }
  2286. ScriptFunction * funcObj = GetJavascriptFunction();
  2287. ScriptFunction::ReparseAsmJsModule(&funcObj);
  2288. const bool doProfile =
  2289. funcObj->GetFunctionBody()->GetInterpreterExecutionMode(false) == ExecutionMode::ProfilingInterpreter ||
  2290. GetScriptContext()->IsInDebugMode() && DynamicProfileInfo::IsEnabled(funcObj->GetFunctionBody());
  2291. DynamicProfileInfo * dynamicProfileInfo = nullptr;
  2292. if (doProfile)
  2293. {
  2294. dynamicProfileInfo = funcObj->GetFunctionBody()->GetDynamicProfileInfo();
  2295. funcObj->GetScriptContext()->GetThreadContext()->ClearImplicitCallFlags();
  2296. }
  2297. // after reparsing, we want to also use a new interpreter stack frame, as it will have different characteristics than the asm.js version
  2298. InterpreterStackFrame::Setup setup(funcObj, m_inParams, m_inSlotsCount);
  2299. size_t varAllocCount = setup.GetAllocationVarCount();
  2300. size_t varSizeInBytes = varAllocCount * sizeof(Var);
  2301. Var* allocation = nullptr;
  2302. DWORD_PTR stackAddr;
  2303. bool fReleaseAlloc = false;
  2304. if (varAllocCount > InterpreterStackFrame::LocalsThreshold)
  2305. {
  2306. ArenaAllocator *tmpAlloc = nullptr;
  2307. fReleaseAlloc = GetScriptContext()->EnsureInterpreterArena(&tmpAlloc);
  2308. allocation = (Var*)tmpAlloc->Alloc(varSizeInBytes);
  2309. // use a stack address so the debugger stepping logic works (step-out, for example, compares stack depths to determine when to complete the step)
  2310. // debugger stepping does not matter here, but it's worth being consistent with normal stack frame
  2311. stackAddr = reinterpret_cast<DWORD_PTR>(&allocation);
  2312. }
  2313. else
  2314. {
  2315. PROBE_STACK_PARTIAL_INITIALIZED_INTERPRETER_FRAME(GetScriptContext(), Js::Constants::MinStackInterpreter + varSizeInBytes);
  2316. allocation = (Var*)_alloca(varSizeInBytes);
  2317. stackAddr = reinterpret_cast<DWORD_PTR>(allocation);
  2318. }
  2319. #if DBG
  2320. Js::RecyclableObject * invalidStackVar = (Js::RecyclableObject*)_alloca(sizeof(Js::RecyclableObject));
  2321. memset(invalidStackVar, 0xFE, sizeof(Js::RecyclableObject));
  2322. InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr, invalidStackVar);
  2323. #else
  2324. InterpreterStackFrame * newInstance = newInstance = setup.InitializeAllocation(allocation, funcObj->GetFunctionBody()->GetHasImplicitArgIns(), doProfile, nullptr, stackAddr);
  2325. #endif
  2326. newInstance->m_reader.Create(funcObj->GetFunctionBody());
  2327. // now that we have set up the new frame, let's interpret it!
  2328. funcObj->GetFunctionBody()->BeginExecution();
  2329. PushPopFrameHelper(newInstance, _ReturnAddress(), _AddressOfReturnAddress());
  2330. Var retVal = newInstance->ProcessUnprofiled();
  2331. if (doProfile)
  2332. {
  2333. dynamicProfileInfo->RecordImplicitCallFlags(GetScriptContext()->GetThreadContext()->GetImplicitCallFlags());
  2334. }
  2335. if (fReleaseAlloc)
  2336. {
  2337. GetScriptContext()->ReleaseInterpreterArena();
  2338. }
  2339. return retVal;
  2340. #else
  2341. Assert(UNREACHED);
  2342. return nullptr;
  2343. #endif
  2344. }
  2345. #if DBG_DUMP
  2346. int AsmJsCallDepth = 0;
  2347. #endif
  2348. void InterpreterStackFrame::PrintStack(const int* const intSrc, const float* const fltSrc, const double* const dblSrc, int intConstCount, int floatConstCount, int doubleConstCount, const wchar_t* state)
  2349. {
  2350. Output::Print(L"\n");
  2351. Output::Print(L"Interpreter Constant Stack Data(%s)\n", state);
  2352. Output::Print(L"***************************************\n");
  2353. Output::Print(L"Int Data\n");
  2354. Output::Print(L"--------\n");
  2355. for (int count = 0; count < intConstCount; count++)
  2356. {
  2357. Output::Print(L"Index:%d Value:%d \n", count, intSrc[count]);
  2358. }
  2359. Output::Print(L"\n");
  2360. Output::Print(L"Float Data\n");
  2361. Output::Print(L"----------\n");
  2362. for (int count = 0; count < floatConstCount; count++)
  2363. {
  2364. Output::Print(L"Index:%d Value:%f \n", count, fltSrc[count]);
  2365. }
  2366. Output::Print(L"\n");
  2367. Output::Print(L"Double Data\n");
  2368. Output::Print(L"-----------\n");
  2369. for (int count = 0; count < doubleConstCount; count++)
  2370. {
  2371. Output::Print(L"Index:%d Value:%g \n", count, dblSrc[count]);
  2372. }
  2373. Output::Print(L"\n");
  2374. }
  2375. #ifndef TEMP_DISABLE_ASMJS
  2376. // Function memory allocation should be done the same way as
  2377. // T AsmJsCommunEntryPoint(Js::ScriptFunction* func, ...) (AsmJSJitTemplate.cpp)
  2378. // update any changes there
  2379. /*
  2380. This function does the following fixup
  2381. Stack Before Stack After
  2382. ============== ================
  2383. | VarConstants | | VarConstants |
  2384. |--------------| |-----------------
  2385. | IntConstants | | IntConstants |
  2386. |--------------| | ------------ |
  2387. | FloatConst | | Int Vars+Tmps |
  2388. |--------------| |----------------|
  2389. | DoubleConst | | FloatConst |
  2390. |--------------| | ---------- |
  2391. | Var&Temps | | Flt Vars+tmps |
  2392. |==============| |----------------|
  2393. | DoubleConst |
  2394. | ----------- |
  2395. | Dbl Vars+Tmps |
  2396. ================
  2397. intSrc,FltSrc&DblSrc are pointers to the stack before the change
  2398. m_localIntSlots,m_localFloatSlots,m_localDoubleSlots are pointers to the stack after the change
  2399. */
  2400. void InterpreterStackFrame::AlignMemoryForAsmJs()
  2401. {
  2402. FunctionBody *const functionBody = GetFunctionBody();
  2403. ScriptFunction* func = GetJavascriptFunction();
  2404. //schedule for codegen here only if TJ is collected
  2405. if (!functionBody->GetIsAsmJsFullJitScheduled() && !PHASE_OFF(BackEndPhase, functionBody)
  2406. && !PHASE_OFF(FullJitPhase, functionBody) && !this->scriptContext->GetConfig()->IsNoNative())
  2407. {
  2408. int callCount = ++((FunctionEntryPointInfo*)func->GetEntryPointInfo())->callsCount;
  2409. bool doSchedule = false;
  2410. const int minAsmJsInterpretRunCount = (int)CONFIG_FLAG(MinAsmJsInterpreterRunCount);
  2411. if (callCount >= minAsmJsInterpretRunCount)
  2412. {
  2413. doSchedule = true;
  2414. }
  2415. if (doSchedule && !functionBody->GetIsAsmJsFullJitScheduled())
  2416. {
  2417. #if ENABLE_NATIVE_CODEGEN
  2418. if (PHASE_TRACE1(AsmjsEntryPointInfoPhase))
  2419. {
  2420. Output::Print(L"Scheduling For Full JIT from Interpreter at callcount:%d\n", callCount);
  2421. }
  2422. GenerateFunction(functionBody->GetScriptContext()->GetNativeCodeGenerator(), functionBody, func);
  2423. #endif
  2424. functionBody->SetIsAsmJsFullJitScheduled(true);
  2425. }
  2426. }
  2427. AsmJsFunctionInfo* info = functionBody->GetAsmJsFunctionInfo();
  2428. const int intConstCount = info->GetIntConstCount();
  2429. const int doubleConstCount = info->GetDoubleConstCount();
  2430. const int floatConstCount = info->GetFloatConstCount();
  2431. const int simdConstCount = info->GetSimdConstCount();
  2432. // Offset of doubles from (double*)m_localSlot
  2433. const int intOffset = info->GetIntByteOffset() / sizeof(int);
  2434. const int doubleOffset = info->GetDoubleByteOffset() / sizeof(double);
  2435. const int floatOffset = info->GetFloatByteOffset() / sizeof(float);
  2436. const int simdByteOffset = info->GetSimdByteOffset();// in bytes;
  2437. int* intSrc = (int*)(m_localSlots + AsmJsFunctionMemory::RequiredVarConstants);
  2438. // Where all int value starts
  2439. m_localIntSlots = ((int*)m_localSlots) + intOffset;
  2440. // where int arguments starts
  2441. // int* intArgDst = m_localIntSlots + intConstCount;
  2442. // Where float constants currently are
  2443. float* floatSrc = (float*)(intSrc + intConstCount);
  2444. // where all float value starts with the new layout
  2445. m_localFloatSlots = ((float*)m_localSlots) + floatOffset;
  2446. // Where double arguments starts
  2447. // float* floatArgDst = m_localFloatSlots + floatConstCount;
  2448. // Where double constants currently are
  2449. double* doubleSrc = (double*)(floatSrc + floatConstCount);
  2450. // where all double value starts
  2451. m_localDoubleSlots = ((double*)m_localSlots) + doubleOffset;
  2452. // Where double arguments starts
  2453. // double* doubleArgDst = m_localDoubleSlots + doubleConstCount;
  2454. AsmJsSIMDValue* simdSrc = nullptr;
  2455. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  2456. {
  2457. simdSrc = (AsmJsSIMDValue*)(doubleSrc + doubleConstCount);
  2458. m_localSimdSlots = (AsmJsSIMDValue*)((char*)m_localSlots + simdByteOffset);
  2459. }
  2460. // Load module environment
  2461. FrameDisplay* frame = this->function->GetEnvironment();
  2462. m_localSlots[AsmJsFunctionMemory::ModuleEnvRegister] = frame->GetItem(0);
  2463. m_localSlots[AsmJsFunctionMemory::ArrayBufferRegister] = (Var*)frame->GetItem(0) + AsmJsModuleMemory::MemoryTableBeginOffset;
  2464. m_localSlots[AsmJsFunctionMemory::ArraySizeRegister] = 0; // do not cache ArraySize in the interpreter
  2465. m_localSlots[AsmJsFunctionMemory::ScriptContextBufferRegister] = functionBody->GetScriptContext();
  2466. if (PHASE_TRACE1(AsmjsInterpreterStackPhase))
  2467. {
  2468. PrintStack(intSrc, floatSrc, doubleSrc, intConstCount, floatConstCount, doubleConstCount, L"Before Shuffling");
  2469. }
  2470. // Copying has to happen in that order in order not to overwrite constants
  2471. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  2472. {
  2473. memcpy_s(m_localSimdSlots, simdConstCount*sizeof(AsmJsSIMDValue), simdSrc, simdConstCount*sizeof(AsmJsSIMDValue));
  2474. }
  2475. // Moving the double and floats to their slot position. We must move the doubles first so that we do not overwrite the doubles stack with floats
  2476. memcpy_s(m_localDoubleSlots, doubleConstCount*sizeof(double), doubleSrc, doubleConstCount*sizeof(double));
  2477. memcpy_s(m_localFloatSlots, floatConstCount*sizeof(float), floatSrc, floatConstCount*sizeof(float));
  2478. if (PHASE_TRACE1(AsmjsInterpreterStackPhase))
  2479. {
  2480. PrintStack(m_localIntSlots, m_localFloatSlots, m_localDoubleSlots, intConstCount, floatConstCount, doubleConstCount, L"After Shuffling");
  2481. }
  2482. int* intArg;
  2483. double* doubleArg;
  2484. float* floatArg;
  2485. intArg = m_localIntSlots + intConstCount;
  2486. doubleArg = m_localDoubleSlots + doubleConstCount;
  2487. floatArg = m_localFloatSlots + floatConstCount;
  2488. AsmJsSIMDValue* simdArg = m_localSimdSlots + simdConstCount;
  2489. // Move the arguments to the right location
  2490. ArgSlot argCount = info->GetArgCount();
  2491. #if _M_X64
  2492. uint homingAreaSize = 0;
  2493. #endif
  2494. uintptr argAddress = (uintptr)m_inParams;
  2495. for (ArgSlot i = 0; i < argCount; i++)
  2496. {
  2497. #if _M_X64
  2498. // 3rd Argument should be at the end of the homing area.
  2499. Assert(i != 3 || argAddress == (uintptr)m_inParams + homingAreaSize);
  2500. if (i < 3)
  2501. {
  2502. // for x64 we spill the first 3 floating point args below the rest of the arguments on the stack
  2503. // m_inParams will be from DynamicInterpreterThunk's frame. Floats are in InterpreterAsmThunk's frame. Stack will be set up like so:
  2504. // DIT arg2 <- first scriptArg, m_inParams points here
  2505. // DIT arg1
  2506. // padding
  2507. // IAT r9 home
  2508. // IAT r8 home
  2509. // IAT rdx home
  2510. // IAT rcx home
  2511. // IAT return address
  2512. // IAT push rbp
  2513. // IAT padding
  2514. // IAT xmm3 spill
  2515. // IAT xmm2 spill
  2516. // IAT xmm1 spill <- floatSpillAddress for arg1
  2517. // floats are spilled as xmmwords
  2518. uintptr floatSpillAddress = (uintptr)m_inParams - MachPtr * (15 - 2*i);
  2519. if (info->GetArgType(i).isInt())
  2520. {
  2521. *intArg = *(int*)argAddress;
  2522. ++intArg;
  2523. homingAreaSize += MachPtr;
  2524. }
  2525. else if (info->GetArgType(i).isFloat())
  2526. {
  2527. *floatArg = *(float*)floatSpillAddress;
  2528. ++floatArg;
  2529. homingAreaSize += MachPtr;
  2530. }
  2531. else if (info->GetArgType(i).isDouble())
  2532. {
  2533. *doubleArg = *(double*)floatSpillAddress;
  2534. ++doubleArg;
  2535. homingAreaSize += MachPtr;
  2536. }
  2537. else
  2538. {
  2539. Assert(info->GetArgType(i).isSIMD());
  2540. *simdArg = *(AsmJsSIMDValue*)floatSpillAddress;
  2541. ++simdArg;
  2542. homingAreaSize += sizeof(AsmJsSIMDValue);
  2543. }
  2544. if (scriptContext->GetConfig()->IsSimdjsEnabled() && i == 2) // last argument ?
  2545. {
  2546. // If we have simd arguments, the homing area in m_inParams can be larger than 3 64-bit slots. This is because SIMD values are unboxed there too.
  2547. // After unboxing, the homing area is overwritten by rdx, r8 and r9, and we read/skip 64-bit slots from the homing area (argAddress += MachPtr).
  2548. // After the last argument of the 3 is read, we need to advance argAddress to skip over the possible extra space and to the start of the rest of the arguments.
  2549. argAddress = (uintptr)m_inParams + homingAreaSize;
  2550. }
  2551. else
  2552. {
  2553. argAddress += MachPtr;
  2554. }
  2555. }
  2556. else
  2557. #endif
  2558. if (info->GetArgType(i).isInt())
  2559. {
  2560. *intArg = *(int*)argAddress;
  2561. ++intArg;
  2562. argAddress += MachPtr;
  2563. }
  2564. else if (info->GetArgType(i).isFloat())
  2565. {
  2566. *floatArg = *(float*)argAddress;
  2567. ++floatArg;
  2568. argAddress += MachPtr;
  2569. }
  2570. else if (info->GetArgType(i).isDouble())
  2571. {
  2572. Assert(info->GetArgType(i).isDouble());
  2573. *doubleArg = *(double*)argAddress;
  2574. ++doubleArg;
  2575. argAddress += sizeof(double);
  2576. }
  2577. else if (scriptContext->GetConfig()->IsSimdjsEnabled() && info->GetArgType(i).isSIMD())
  2578. {
  2579. *simdArg = *(AsmJsSIMDValue*)argAddress;
  2580. ++simdArg;
  2581. argAddress += sizeof(AsmJsSIMDValue);
  2582. }
  2583. else
  2584. {
  2585. AssertMsg(UNREACHED, "Invalid function arg type.");
  2586. }
  2587. }
  2588. #if DBG_DUMP
  2589. const bool tracingFunc = PHASE_TRACE( AsmjsFunctionEntryPhase, functionBody );
  2590. if( tracingFunc )
  2591. {
  2592. if( AsmJsCallDepth )
  2593. {
  2594. Output::Print( L"%*c", AsmJsCallDepth,' ');
  2595. }
  2596. Output::Print( L"Executing function %s", functionBody->GetDisplayName());
  2597. ++AsmJsCallDepth;
  2598. }
  2599. #endif
  2600. #if DBG_DUMP
  2601. if (tracingFunc)
  2602. {
  2603. Output::Print(L"){\n");
  2604. }
  2605. #endif
  2606. if( info->GetReturnType() == AsmJsRetType::Void )
  2607. {
  2608. m_localSlots[0] = JavascriptOperators::OP_LdUndef( scriptContext );
  2609. }
  2610. }
  2611. #endif
  2612. ///----------------------------------------------------------------------------
  2613. ///
  2614. /// InterpreterStackFrame::Process
  2615. ///
  2616. /// Process() processes a single loop of execution for the current
  2617. /// JavascriptFunction being executed:
  2618. /// - Individual instructions are dispatched to specific handlers for different
  2619. /// OpCodes.
  2620. ///
  2621. ///----------------------------------------------------------------------------
  2622. #if ENABLE_PROFILE_INFO
  2623. #define INTERPRETERLOOPNAME ProcessProfiled
  2624. #define PROVIDE_INTERPRETERPROFILE
  2625. #include "Interpreterloop.inl"
  2626. #undef PROVIDE_INTERPRETERPROFILE
  2627. #undef INTERPRETERLOOPNAME
  2628. #endif
  2629. #define INTERPRETERLOOPNAME ProcessUnprofiled
  2630. #include "Interpreterloop.inl"
  2631. #undef INTERPRETERLOOPNAME
  2632. #ifndef TEMP_DISABLE_ASMJS
  2633. #define INTERPRETERLOOPNAME ProcessAsmJs
  2634. #define INTERPRETER_ASMJS
  2635. #include "InterpreterProcessOpCodeAsmJs.h"
  2636. #include "Interpreterloop.inl"
  2637. #undef INTERPRETER_ASMJS
  2638. #undef INTERPRETERLOOPNAME
  2639. #endif
  2640. // For now, always collect profile data when debugging,
  2641. // otherwise the backend will be confused if there's no profile data.
  2642. #define INTERPRETERLOOPNAME ProcessWithDebugging
  2643. #define PROVIDE_DEBUGGING
  2644. #if ENABLE_PROFILE_INFO
  2645. #define PROVIDE_INTERPRETERPROFILE
  2646. #endif
  2647. #include "Interpreterloop.inl"
  2648. #if ENABLE_PROFILE_INFO
  2649. #undef PROVIDE_INTERPRETERPROFILE
  2650. #endif
  2651. #undef PROVIDE_DEBUGGING
  2652. #undef INTERPRETERLOOPNAME
  2653. Var InterpreterStackFrame::Process()
  2654. {
  2655. #if ENABLE_PROFILE_INFO
  2656. class AutoRestore
  2657. {
  2658. private:
  2659. InterpreterStackFrame *const interpreterStackFrame;
  2660. const uint32 savedSwitchProfileModeOnLoopEndNumber;
  2661. const bool savedIsAutoProfiling;
  2662. const bool savedSwitchProfileMode;
  2663. public:
  2664. AutoRestore(InterpreterStackFrame *const interpreterStackFrame)
  2665. : interpreterStackFrame(interpreterStackFrame),
  2666. savedIsAutoProfiling(interpreterStackFrame->isAutoProfiling),
  2667. savedSwitchProfileMode(interpreterStackFrame->switchProfileMode),
  2668. savedSwitchProfileModeOnLoopEndNumber(interpreterStackFrame->switchProfileModeOnLoopEndNumber)
  2669. {
  2670. }
  2671. ~AutoRestore()
  2672. {
  2673. interpreterStackFrame->isAutoProfiling = savedIsAutoProfiling;
  2674. interpreterStackFrame->switchProfileMode = savedSwitchProfileMode;
  2675. interpreterStackFrame->switchProfileModeOnLoopEndNumber = savedSwitchProfileModeOnLoopEndNumber;
  2676. }
  2677. } autoRestore(this);
  2678. #endif
  2679. if ((m_flags & Js::InterpreterStackFrameFlags_FromBailOut) && !(m_flags & InterpreterStackFrameFlags_ProcessingBailOutFromEHCode))
  2680. {
  2681. if (this->ehBailoutData)
  2682. {
  2683. m_flags |= Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
  2684. EHBailoutData * topLevelEHBailoutData = this->ehBailoutData;
  2685. while (topLevelEHBailoutData->parent->nestingDepth != -1)
  2686. {
  2687. topLevelEHBailoutData->parent->child = topLevelEHBailoutData;
  2688. topLevelEHBailoutData = topLevelEHBailoutData->parent;
  2689. }
  2690. ProcessTryCatchBailout(topLevelEHBailoutData, this->ehBailoutData->nestingDepth);
  2691. m_flags &= ~Js::InterpreterStackFrameFlags_ProcessingBailOutFromEHCode;
  2692. this->ehBailoutData = nullptr;
  2693. }
  2694. }
  2695. #ifndef TEMP_DISABLE_ASMJS
  2696. FunctionBody *const functionBody = GetFunctionBody();
  2697. if( functionBody->GetIsAsmjsMode() )
  2698. {
  2699. AsmJsFunctionInfo* asmInfo = functionBody->GetAsmJsFunctionInfo();
  2700. if (asmInfo)
  2701. {
  2702. AlignMemoryForAsmJs();
  2703. Var returnVar = ProcessAsmJs();
  2704. #if DBG_DUMP
  2705. if( PHASE_TRACE( AsmjsFunctionEntryPhase, functionBody ) )
  2706. {
  2707. --AsmJsCallDepth;
  2708. if( AsmJsCallDepth )
  2709. {
  2710. Output::Print( L"%*c}", AsmJsCallDepth, ' ' );
  2711. }
  2712. else
  2713. {
  2714. Output::Print( L"}" );
  2715. }
  2716. switch( asmInfo->GetReturnType().which() )
  2717. {
  2718. case AsmJsRetType::Void:
  2719. break;
  2720. case AsmJsRetType::Signed:
  2721. Output::Print( L" = %d", JavascriptMath::ToInt32( returnVar, scriptContext ) );
  2722. break;
  2723. case AsmJsRetType::Float:
  2724. case AsmJsRetType::Double:
  2725. Output::Print( L" = %.4f", JavascriptConversion::ToNumber( returnVar, scriptContext ) );
  2726. break;
  2727. default:
  2728. break;
  2729. }
  2730. Output::Print( L";\n" );
  2731. }
  2732. #endif
  2733. return returnVar;
  2734. }
  2735. else
  2736. {
  2737. Assert(functionBody->GetAsmJsModuleInfo());
  2738. return ProcessAsmJsModule();
  2739. }
  2740. }
  2741. #endif
  2742. #if ENABLE_PROFILE_INFO
  2743. switchProfileMode = false;
  2744. switchProfileModeOnLoopEndNumber = 0u - 1;
  2745. #endif
  2746. #if ENABLE_PROFILE_INFO
  2747. const ExecutionMode interpreterExecutionMode =
  2748. functionBody->GetInterpreterExecutionMode(!!(GetFlags() & InterpreterStackFrameFlags_FromBailOut));
  2749. if(interpreterExecutionMode == ExecutionMode::ProfilingInterpreter)
  2750. {
  2751. isAutoProfiling = false;
  2752. return ProcessProfiled();
  2753. }
  2754. Assert(
  2755. interpreterExecutionMode == ExecutionMode::Interpreter ||
  2756. interpreterExecutionMode == ExecutionMode::AutoProfilingInterpreter);
  2757. isAutoProfiling = interpreterExecutionMode == ExecutionMode::AutoProfilingInterpreter;
  2758. Var result;
  2759. while(true)
  2760. {
  2761. Assert(!switchProfileMode);
  2762. result = ProcessUnprofiled();
  2763. Assert(!(switchProfileMode && result));
  2764. if(switchProfileMode)
  2765. {
  2766. switchProfileMode = false;
  2767. }
  2768. else
  2769. {
  2770. break;
  2771. }
  2772. Assert(isAutoProfiling);
  2773. #if DBG_DUMP
  2774. if(PHASE_TRACE(InterpreterAutoProfilePhase, functionBody))
  2775. {
  2776. wchar_t debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2777. Output::Print(L"InterpreterAutoProfile - Func %s - Started profiling\n", functionBody->GetDebugNumberSet(debugStringBuffer));
  2778. Output::Flush();
  2779. }
  2780. #endif
  2781. Assert(!switchProfileMode);
  2782. result = ProcessProfiled();
  2783. Assert(!(switchProfileMode && result));
  2784. if(switchProfileMode)
  2785. {
  2786. switchProfileMode = false;
  2787. }
  2788. else
  2789. {
  2790. break;
  2791. }
  2792. Assert(isAutoProfiling);
  2793. #if DBG_DUMP
  2794. if(PHASE_TRACE(InterpreterAutoProfilePhase, functionBody))
  2795. {
  2796. wchar_t debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  2797. Output::Print(L"InterpreterAutoProfile - Func %s - Stopped profiling\n", functionBody->GetDebugNumberSet(debugStringBuffer));
  2798. Output::Flush();
  2799. }
  2800. #endif
  2801. }
  2802. return result;
  2803. #else
  2804. return ProcessUnprofiled();
  2805. #endif
  2806. }
  2807. template <class T>
  2808. void InterpreterStackFrame::OP_GetMethodProperty(unaligned T *playout)
  2809. {
  2810. Var varInstance = GetReg(playout->Instance);
  2811. OP_GetMethodProperty(varInstance, playout);
  2812. }
  2813. template <class T>
  2814. void InterpreterStackFrame::OP_GetLocalMethodProperty(unaligned T *playout)
  2815. {
  2816. OP_GetMethodProperty(this->localClosure, playout);
  2817. }
  2818. template <class T>
  2819. void InterpreterStackFrame::OP_GetMethodProperty(Var varInstance, unaligned T *playout)
  2820. {
  2821. #if ENABLE_COPYONACCESS_ARRAY
  2822. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(varInstance);
  2823. #endif
  2824. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  2825. RecyclableObject* obj = NULL;
  2826. if (RecyclableObject::Is(varInstance))
  2827. {
  2828. obj = RecyclableObject::FromVar(varInstance);
  2829. if ((propertyId == PropertyIds::apply || propertyId == PropertyIds::call) && ScriptFunction::Is(obj))
  2830. {
  2831. // If the property being loaded is "apply"/"call", make an optimistic assumption that apply/call is not overridden and
  2832. // undefer the function right here if it was defer parsed before. This is required so that the load of "apply"/"call"
  2833. // happens from the same "type". Otherwise, we will have a polymorphic cache for load of "apply"/"call".
  2834. ScriptFunction *fn = ScriptFunction::FromVar(obj);
  2835. if(fn->GetType()->GetEntryPoint() == JavascriptFunction::DeferredParsingThunk)
  2836. {
  2837. JavascriptFunction::DeferredParse(&fn);
  2838. }
  2839. }
  2840. }
  2841. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  2842. PropertyValueInfo info;
  2843. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  2844. Var aValue;
  2845. if (obj &&
  2846. CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
  2847. obj, false, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
  2848. {
  2849. SetReg(playout->Value, aValue);
  2850. return;
  2851. }
  2852. OP_GetMethodProperty_NoFastPath(varInstance, playout);
  2853. }
  2854. template <class T>
  2855. __declspec(noinline) void InterpreterStackFrame::OP_GetMethodProperty_NoFastPath(Var instance, unaligned T *playout)
  2856. {
  2857. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  2858. Var value = JavascriptOperators::PatchGetMethod<false>(
  2859. GetFunctionBody(),
  2860. GetInlineCache(playout->inlineCacheIndex),
  2861. playout->inlineCacheIndex,
  2862. instance,
  2863. propertyId
  2864. );
  2865. #ifdef TELEMETRY_INTERPRETER
  2866. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  2867. {
  2868. // `successful` will be true as PatchGetMethod throws an exception if not found.
  2869. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(instance, propertyId, value, true);
  2870. }
  2871. #endif
  2872. SetReg(playout->Value, value);
  2873. }
  2874. template <class T>
  2875. void InterpreterStackFrame::OP_GetRootMethodProperty(unaligned T *playout)
  2876. {
  2877. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  2878. Js::Var instance = this->GetRootObject();
  2879. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  2880. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  2881. DynamicObject *obj = DynamicObject::FromVar(instance);
  2882. PropertyValueInfo info;
  2883. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  2884. Var aValue;
  2885. if (CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
  2886. obj, true, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
  2887. {
  2888. SetReg(playout->Value, aValue);
  2889. return;
  2890. }
  2891. OP_GetRootMethodProperty_NoFastPath(playout);
  2892. }
  2893. template <class T>
  2894. __declspec(noinline) void InterpreterStackFrame::OP_GetRootMethodProperty_NoFastPath(unaligned T *playout)
  2895. {
  2896. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  2897. Var rootInstance = this->GetRootObject();
  2898. Var value = JavascriptOperators::PatchGetRootMethod<false>(
  2899. GetFunctionBody(),
  2900. GetInlineCache(playout->inlineCacheIndex),
  2901. playout->inlineCacheIndex,
  2902. DynamicObject::FromVar(rootInstance),
  2903. propertyId
  2904. );
  2905. #ifdef TELEMETRY_INTERPRETER
  2906. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  2907. {
  2908. // `successful` will be true as PatchGetMethod throws an exception if not found.
  2909. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(rootInstance, propertyId, value, true);
  2910. }
  2911. #endif
  2912. SetReg(playout->Value, value);
  2913. }
  2914. template <class T>
  2915. void InterpreterStackFrame::OP_GetMethodPropertyScoped(unaligned T *playout)
  2916. {
  2917. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  2918. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  2919. threadContext->ClearImplicitCallFlags();
  2920. Var varInstance = GetReg(playout->Instance);
  2921. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  2922. RecyclableObject* obj = NULL;
  2923. if (RecyclableObject::Is(varInstance))
  2924. {
  2925. obj = RecyclableObject::FromVar(varInstance);
  2926. }
  2927. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  2928. PropertyValueInfo info;
  2929. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  2930. Var aValue;
  2931. if (obj &&
  2932. CacheOperators::TryGetProperty<true, true, false, false, false, false, true, false, false>(
  2933. obj, false, obj, propertyId, &aValue, GetScriptContext(), nullptr, &info))
  2934. {
  2935. threadContext->CheckAndResetImplicitCallAccessorFlag();
  2936. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  2937. SetReg(playout->Value, aValue);
  2938. return;
  2939. }
  2940. OP_GetMethodPropertyScoped_NoFastPath(playout);
  2941. threadContext->CheckAndResetImplicitCallAccessorFlag();
  2942. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  2943. }
  2944. template <class T>
  2945. __declspec(noinline) void InterpreterStackFrame::OP_GetMethodPropertyScoped_NoFastPath(unaligned T *playout)
  2946. {
  2947. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  2948. Js::Var instance = GetReg(playout->Instance);
  2949. Js::Var value = JavascriptOperators::PatchScopedGetMethod<false>(
  2950. GetFunctionBody(),
  2951. GetInlineCache(playout->inlineCacheIndex),
  2952. playout->inlineCacheIndex,
  2953. instance,
  2954. propertyId
  2955. );
  2956. SetReg(playout->Value, value);
  2957. #ifdef TELEMETRY_INTERPRETER
  2958. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  2959. {
  2960. // `successful` will be true as PatchGetMethod throws an exception if not found.
  2961. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetMethodProperty(instance, propertyId, value, true);
  2962. }
  2963. #endif
  2964. }
  2965. template <class T>
  2966. void InterpreterStackFrame::OP_ProfiledGetMethodProperty(unaligned T *playout)
  2967. {
  2968. ProfiledGetProperty<T, false, true, false>(playout, GetReg(playout->Instance));
  2969. }
  2970. template <class T>
  2971. void InterpreterStackFrame::OP_ProfiledGetLocalMethodProperty(unaligned T *playout)
  2972. {
  2973. ProfiledGetProperty<T, false, true, false>(playout, this->localClosure);
  2974. }
  2975. template <class T>
  2976. void InterpreterStackFrame::OP_ProfiledGetRootMethodProperty(unaligned T *playout)
  2977. {
  2978. ProfiledGetProperty<T, true, true, false>(playout, GetRootObject());
  2979. }
  2980. RecyclableObject *
  2981. InterpreterStackFrame::OP_CallGetFunc(Var target)
  2982. {
  2983. return JavascriptOperators::GetCallableObjectOrThrow(target, GetScriptContext());
  2984. }
  2985. void InterpreterStackFrame::OP_AsmStartCall( const unaligned OpLayoutStartCall * playout )
  2986. {
  2987. OP_StartCall( playout->ArgCount/sizeof(Var) );
  2988. m_outParams[0] = scriptContext->GetLibrary()->GetUndefined();
  2989. }
  2990. void InterpreterStackFrame::OP_StartCall(const unaligned OpLayoutStartCall * playout)
  2991. {
  2992. OP_StartCall(playout->ArgCount);
  2993. }
  2994. void InterpreterStackFrame::OP_StartCall(uint outParamCount)
  2995. {
  2996. // Save the outParams for the current callsite on the outparam stack
  2997. PushOut(m_outParams);
  2998. // Update outParams for the indicated callsite
  2999. m_outParams = m_outSp;
  3000. m_outSp += outParamCount;
  3001. AssertMsg(m_localSlots + this->m_functionBody->GetLocalsCount() < m_outSp &&
  3002. m_outSp <= (m_localSlots + this->m_functionBody->GetLocalsCount() + this->m_functionBody->GetOutParamsDepth()),
  3003. "out args Stack pointer not in range after Push");
  3004. }
  3005. #ifndef TEMP_DISABLE_ASMJS
  3006. #if _M_X64
  3007. void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
  3008. {
  3009. AsmJsFunctionInfo* asmInfo = ((ScriptFunction*)function)->GetFunctionBody()->GetAsmJsFunctionInfo();
  3010. uint argsSize = asmInfo->GetArgByteSize();
  3011. ScriptFunction* scriptFunc = (ScriptFunction*)function;
  3012. ScriptContext * scriptContext = function->GetScriptContext();
  3013. PROBE_STACK_CALL(scriptContext, function, argsSize);
  3014. Js::FunctionEntryPointInfo* entrypointInfo = (Js::FunctionEntryPointInfo*)scriptFunc->GetEntryPointInfo();
  3015. switch (asmInfo->GetReturnType().which())
  3016. {
  3017. case AsmJsRetType::Void:
  3018. case AsmJsRetType::Signed:
  3019. m_localIntSlots[0] = JavascriptFunction::CallAsmJsFunction<int>(function, entrypointInfo->address, asmInfo->GetArgCount(), m_outParams);
  3020. break;
  3021. case AsmJsRetType::Double:
  3022. m_localDoubleSlots[0] = JavascriptFunction::CallAsmJsFunction<double>(function, entrypointInfo->address, asmInfo->GetArgCount(), m_outParams);
  3023. break;
  3024. case AsmJsRetType::Float:
  3025. m_localFloatSlots[0] = JavascriptFunction::CallAsmJsFunction<float>(function, entrypointInfo->address, asmInfo->GetArgCount(), m_outParams);
  3026. break;
  3027. case AsmJsRetType::Float32x4:
  3028. case AsmJsRetType::Int32x4:
  3029. case AsmJsRetType::Float64x2:
  3030. X86SIMDValue simdVal;
  3031. simdVal.m128_value = JavascriptFunction::CallAsmJsFunction<__m128>(function, entrypointInfo->address, asmInfo->GetArgCount(), m_outParams);
  3032. m_localSimdSlots[0] = X86SIMDValue::ToSIMDValue(simdVal);
  3033. break;
  3034. }
  3035. Assert((uint)((ArgSlot)asmInfo->GetArgCount() + 1) == (uint)(asmInfo->GetArgCount() + 1));
  3036. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  3037. {
  3038. PopOut((ArgSlot)(asmInfo->GetArgByteSize() / sizeof(Var)) + 1);
  3039. }
  3040. else
  3041. {
  3042. PopOut((ArgSlot)asmInfo->GetArgCount() + 1);
  3043. }
  3044. Assert(function);
  3045. }
  3046. #elif _M_IX86
  3047. void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
  3048. {
  3049. enum {
  3050. Void = AsmJsRetType::Void,
  3051. Signed = AsmJsRetType::Signed,
  3052. Float = AsmJsRetType::Float,
  3053. Double = AsmJsRetType::Double,
  3054. Int32x4 = AsmJsRetType::Int32x4,
  3055. Float32x4 = AsmJsRetType::Float32x4,
  3056. Float64x2 = AsmJsRetType::Float64x2
  3057. };
  3058. AsmJsFunctionInfo* asmInfo = ((ScriptFunction*)function)->GetFunctionBody()->GetAsmJsFunctionInfo();
  3059. Assert((uint)((ArgSlot)asmInfo->GetArgCount() + 1) == (uint)(asmInfo->GetArgCount() + 1));
  3060. uint argsSize = asmInfo->GetArgByteSize();
  3061. uint alignedSize = ::Math::Align<int32>(argsSize, 8);
  3062. ScriptFunction* scriptFunc = (ScriptFunction*)function;
  3063. ScriptContext * scriptContext = function->GetScriptContext();
  3064. PROBE_STACK_CALL(scriptContext, function, alignedSize);
  3065. Js::FunctionEntryPointInfo* entrypointInfo = (Js::FunctionEntryPointInfo*)scriptFunc->GetEntryPointInfo();
  3066. int retIntVal = NULL;
  3067. float retFloatVal = NULL;
  3068. double retDoubleVal = NULL;
  3069. AsmJsSIMDValue retSimdVal;
  3070. retSimdVal.Zero();
  3071. AsmJsRetType::Which retType = (AsmJsRetType::Which) GetRetType(scriptFunc);
  3072. void *data = nullptr;
  3073. JavascriptMethod entryPoint = (JavascriptMethod)entrypointInfo->address;
  3074. void *savedEsp = nullptr;
  3075. __asm
  3076. {
  3077. // Save ESP
  3078. mov savedEsp, esp;
  3079. mov eax, alignedSize;
  3080. // Make sure we don't go beyond guard page
  3081. cmp eax, 0x1000;
  3082. jge alloca_probe;
  3083. sub esp, eax;
  3084. jmp dbl_align;
  3085. alloca_probe :
  3086. // Use alloca to allocate more then a page size
  3087. // Alloca assumes eax, contains size, and adjust ESP while
  3088. // probing each page.
  3089. call _alloca_probe_16;
  3090. dbl_align :
  3091. and esp,-8
  3092. mov data, esp;
  3093. }
  3094. {
  3095. Var* outParam = m_outParams + 1;
  3096. void* dest = (void*)data;
  3097. memmove(dest, outParam, argsSize);
  3098. }
  3099. // call variable argument function provided in entryPoint
  3100. __asm
  3101. {
  3102. #ifdef _CONTROL_FLOW_GUARD
  3103. // verify that the call target is valid
  3104. mov ecx, entryPoint
  3105. call[__guard_check_icall_fptr]
  3106. ; no need to restore ecx('call entryPoint' is a __cdecl call)
  3107. #endif
  3108. push function;
  3109. call entryPoint;
  3110. mov ebx, retType;
  3111. cmp ebx, Void;
  3112. je VoidLabel;
  3113. cmp ebx, Signed;
  3114. je SignedLabel;
  3115. cmp ebx, Float;
  3116. je FloatLabel;
  3117. cmp ebx, Double;
  3118. je DoubleLabel;
  3119. // simd
  3120. movups retSimdVal, xmm0;
  3121. jmp end
  3122. VoidLabel:
  3123. SignedLabel:
  3124. mov retIntVal, eax;
  3125. jmp end;
  3126. FloatLabel:
  3127. movss retFloatVal, xmm0;
  3128. jmp end;
  3129. DoubleLabel:
  3130. movsd retDoubleVal, xmm0;
  3131. end:
  3132. // Restore ESP
  3133. mov esp, savedEsp;
  3134. }
  3135. switch (retType)
  3136. {
  3137. case AsmJsRetType::Int32x4:
  3138. case AsmJsRetType::Float32x4:
  3139. case AsmJsRetType::Float64x2:
  3140. if (scriptContext->GetConfig()->IsSimdjsEnabled())
  3141. {
  3142. m_localSimdSlots[0] = retSimdVal;
  3143. break;
  3144. }
  3145. Assert(UNREACHED);
  3146. case AsmJsRetType::Double:
  3147. m_localDoubleSlots[0] = retDoubleVal;
  3148. break;
  3149. case AsmJsRetType::Float:
  3150. m_localFloatSlots[0] = retFloatVal;
  3151. break;
  3152. case AsmJsRetType::Signed:
  3153. case AsmJsRetType::Void:
  3154. m_localIntSlots[0] = retIntVal;
  3155. break;
  3156. default:
  3157. Assume(false);
  3158. }
  3159. PopOut((uint)((ArgSlot)argsSize/sizeof(Var)) + 1);
  3160. Assert(function);
  3161. }
  3162. #else
  3163. void InterpreterStackFrame::OP_CallAsmInternal(RecyclableObject * function)
  3164. {
  3165. __debugbreak();
  3166. }
  3167. #endif
  3168. #endif
  3169. template <class T>
  3170. void InterpreterStackFrame::OP_AsmCall(const unaligned T* playout)
  3171. {
  3172. OP_CallCommon(playout, OP_CallGetFunc(GetRegAllowStackVar(playout->Function)), CallFlags_None);
  3173. AsmJsModuleInfo::EnsureHeapAttached(this->function);
  3174. }
  3175. template <class T>
  3176. void InterpreterStackFrame::OP_CallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, const Js::AuxArray<uint32> *spreadIndices)
  3177. {
  3178. // Always save and restore implicit call flags when calling out
  3179. // REVIEW: Can we avoid it if we don't collect dynamic profile info?
  3180. ThreadContext * threadContext = scriptContext->GetThreadContext();
  3181. Js::ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3182. #if DBG
  3183. if (scriptContext->IsInDebugMode())
  3184. {
  3185. JavascriptFunction::CheckValidDebugThunk(scriptContext, function);
  3186. }
  3187. #endif
  3188. if (playout->Return == Js::Constants::NoRegister)
  3189. {
  3190. flags |= CallFlags_NotUsed;
  3191. Arguments args(CallInfo((CallFlags)flags, playout->ArgCount), m_outParams);
  3192. AssertMsg(args.Info.Flags == flags, "Flags don't fit into the CallInfo field?");
  3193. if (spreadIndices != nullptr)
  3194. {
  3195. JavascriptFunction::CallSpreadFunction(function, function->GetEntryPoint(), args, spreadIndices);
  3196. }
  3197. else
  3198. {
  3199. JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args);
  3200. }
  3201. }
  3202. else
  3203. {
  3204. flags |= CallFlags_Value;
  3205. Arguments args(CallInfo((CallFlags)flags, playout->ArgCount), m_outParams);
  3206. AssertMsg(args.Info.Flags == flags, "Flags don't fit into the CallInfo field?");
  3207. if (spreadIndices != nullptr)
  3208. {
  3209. SetReg((RegSlot)playout->Return, JavascriptFunction::CallSpreadFunction(function, function->GetEntryPoint(), args, spreadIndices));
  3210. }
  3211. else
  3212. {
  3213. SetReg((RegSlot)playout->Return, JavascriptFunction::CallFunction<true>(function, function->GetEntryPoint(), args));
  3214. }
  3215. }
  3216. threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
  3217. PopOut(playout->ArgCount);
  3218. }
  3219. template <class T>
  3220. void InterpreterStackFrame::OP_CallCommonI(const unaligned T * playout, RecyclableObject * function, unsigned flags)
  3221. {
  3222. OP_CallCommon(playout, function, flags); // CallCommon doesn't do anything with Member
  3223. }
  3224. #if ENABLE_PROFILE_INFO
  3225. template <class T>
  3226. void InterpreterStackFrame::OP_ProfileCallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, ProfileId profileId, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
  3227. {
  3228. FunctionBody* functionBody = this->m_functionBody;
  3229. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  3230. FunctionInfo* functionInfo = function->GetTypeId() == TypeIds_Function?
  3231. JavascriptFunction::FromVar(function)->GetFunctionInfo() : nullptr;
  3232. dynamicProfileInfo->RecordCallSiteInfo(functionBody, profileId, functionInfo, functionInfo ? static_cast<JavascriptFunction*>(function) : nullptr, playout->ArgCount, false, inlineCacheIndex);
  3233. OP_CallCommon<T>(playout, function, flags, spreadIndices);
  3234. if (playout->Return != Js::Constants::NoRegister)
  3235. {
  3236. dynamicProfileInfo->RecordReturnTypeOnCallSiteInfo(functionBody, profileId, GetReg((RegSlot)playout->Return));
  3237. }
  3238. }
  3239. template <class T>
  3240. void InterpreterStackFrame::OP_ProfileReturnTypeCallCommon(const unaligned T * playout, RecyclableObject * function, unsigned flags, ProfileId profileId, const Js::AuxArray<uint32> *spreadIndices)
  3241. {
  3242. OP_CallCommon<T>(playout, function, flags, spreadIndices);
  3243. FunctionBody* functionBody = this->m_functionBody;
  3244. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  3245. if (playout->Return != Js::Constants::NoRegister)
  3246. {
  3247. dynamicProfileInfo->RecordReturnType(functionBody, profileId, GetReg((RegSlot)playout->Return));
  3248. }
  3249. }
  3250. #endif
  3251. template <class T>
  3252. void InterpreterStackFrame::OP_CallPutCommon(const unaligned T *playout, RecyclableObject * function)
  3253. {
  3254. Arguments args(CallInfo(CallFlags_None, playout->ArgCount), m_outParams);
  3255. SetReg((RegSlot)playout->Return, function->InvokePut(args));
  3256. PopOut(playout->ArgCount);
  3257. }
  3258. template <class T>
  3259. void InterpreterStackFrame::OP_CallPutCommonI(const unaligned T *playout, RecyclableObject * function)
  3260. {
  3261. OP_CallPutCommon(playout, function);
  3262. }
  3263. template <class T>
  3264. void InterpreterStackFrame::OP_GetRootProperty(unaligned T* playout)
  3265. {
  3266. // Same fast path as in the backend.
  3267. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  3268. Js::Var instance = this->GetRootObject();
  3269. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3270. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3271. DynamicObject * obj = DynamicObject::FromVar(instance);
  3272. PropertyValueInfo info;
  3273. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3274. Var value;
  3275. if(CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3276. obj, true, obj, propertyId, &value, GetScriptContext(), nullptr, &info))
  3277. {
  3278. SetReg(playout->Value, value);
  3279. return;
  3280. }
  3281. OP_GetRootProperty_NoFastPath(playout);
  3282. }
  3283. template <class T>
  3284. void InterpreterStackFrame::OP_GetRootPropertyForTypeOf(unaligned T* playout)
  3285. {
  3286. Var rootInstance = GetRootObject();
  3287. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3288. Var value = JavascriptOperators::PatchGetRootValueForTypeOf<false>(
  3289. GetFunctionBody(),
  3290. GetInlineCache(playout->inlineCacheIndex),
  3291. playout->inlineCacheIndex,
  3292. DynamicObject::FromVar(rootInstance),
  3293. propertyId
  3294. );
  3295. SetReg(playout->Value, value);
  3296. #ifdef TELEMETRY_INTERPRETER
  3297. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3298. {
  3299. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3300. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
  3301. }
  3302. #endif
  3303. }
  3304. template <class T>
  3305. __declspec(noinline) void InterpreterStackFrame::OP_GetRootProperty_NoFastPath(unaligned T* playout)
  3306. {
  3307. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3308. Var rootInstance = this->GetRootObject();
  3309. Var value = JavascriptOperators::PatchGetRootValue<false>(
  3310. GetFunctionBody(),
  3311. GetInlineCache(playout->inlineCacheIndex),
  3312. playout->inlineCacheIndex,
  3313. DynamicObject::FromVar(rootInstance),
  3314. propertyId
  3315. );
  3316. SetReg(playout->Value, value);
  3317. #ifdef TELEMETRY_INTERPRETER
  3318. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3319. {
  3320. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3321. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
  3322. }
  3323. #endif
  3324. }
  3325. #if ENABLE_PROFILE_INFO
  3326. template <class T>
  3327. void InterpreterStackFrame::UpdateFldInfoFlagsForGetSetInlineCandidate(unaligned T* playout, FldInfoFlags& fldInfoFlags, CacheType cacheType,
  3328. DynamicProfileInfo * dynamicProfileInfo, uint inlineCacheIndex, RecyclableObject * obj)
  3329. {
  3330. RecyclableObject *callee = nullptr;
  3331. //TODO: Setter case once we stop sharing inline caches for these callsites.
  3332. if ((cacheType & (CacheType_Getter | CacheType_Setter)) && GetInlineCache(inlineCacheIndex)->GetGetterSetter(obj->GetType(), &callee))
  3333. {
  3334. const auto functionBody = this->m_functionBody;
  3335. bool canInline = dynamicProfileInfo->RecordLdFldCallSiteInfo(functionBody, callee, false /*callApplyTarget*/);
  3336. if (canInline)
  3337. {
  3338. //updates this fldInfoFlags passed by reference.
  3339. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
  3340. }
  3341. }
  3342. }
  3343. template <class T>
  3344. void InterpreterStackFrame::UpdateFldInfoFlagsForCallApplyInlineCandidate(unaligned T* playout, FldInfoFlags& fldInfoFlags, CacheType cacheType,
  3345. DynamicProfileInfo * dynamicProfileInfo, uint inlineCacheIndex, RecyclableObject * obj)
  3346. {
  3347. RecyclableObject *callee = nullptr;
  3348. if (!(fldInfoFlags & FldInfo_Polymorphic) && GetInlineCache(inlineCacheIndex)->GetCallApplyTarget(obj, &callee))
  3349. {
  3350. const auto functionBody = this->m_functionBody;
  3351. bool canInline = dynamicProfileInfo->RecordLdFldCallSiteInfo(functionBody, callee, true /*callApplyTarget*/);
  3352. if (canInline)
  3353. {
  3354. //updates this fldInfoFlags passed by reference.
  3355. fldInfoFlags = DynamicProfileInfo::MergeFldInfoFlags(fldInfoFlags, FldInfo_InlineCandidate);
  3356. }
  3357. }
  3358. }
  3359. template <class T, bool Root, bool Method, bool CallApplyTarget>
  3360. void InterpreterStackFrame::ProfiledGetProperty(unaligned T* playout, const Var instance)
  3361. {
  3362. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3363. Var value = ProfilingHelpers::ProfiledLdFld<Root, Method, CallApplyTarget>(
  3364. instance,
  3365. propertyId,
  3366. GetInlineCache(playout->inlineCacheIndex),
  3367. playout->inlineCacheIndex,
  3368. GetFunctionBody(),
  3369. instance);
  3370. SetReg(playout->Value, value);
  3371. #ifdef TELEMETRY_INTERPRETER
  3372. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3373. {
  3374. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3375. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful:*/true);
  3376. }
  3377. #endif
  3378. }
  3379. template <class T>
  3380. void InterpreterStackFrame::OP_ProfiledGetRootProperty(unaligned T* playout)
  3381. {
  3382. ProfiledGetProperty<T, true, false, false>(playout, GetRootObject());
  3383. }
  3384. template <class T>
  3385. void InterpreterStackFrame::OP_ProfiledGetRootPropertyForTypeOf(unaligned T* playout)
  3386. {
  3387. Var rootInstance = GetRootObject();
  3388. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3389. Var value = ProfilingHelpers::ProfiledLdFldForTypeOf<true, false, false>(
  3390. rootInstance,
  3391. propertyId,
  3392. GetInlineCache(playout->inlineCacheIndex),
  3393. playout->inlineCacheIndex,
  3394. GetFunctionBody());
  3395. SetReg(playout->Value, value);
  3396. #ifdef TELEMETRY_INTERPRETER
  3397. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3398. {
  3399. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3400. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(rootInstance, propertyId, value, /*successful:*/true);
  3401. }
  3402. #endif
  3403. }
  3404. #endif
  3405. template <class T>
  3406. void InterpreterStackFrame::OP_GetPropertyForTypeOf(unaligned T* playout)
  3407. {
  3408. Var instance = GetReg(playout->Instance);
  3409. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3410. Var value = JavascriptOperators::PatchGetValueForTypeOf<false>(
  3411. GetFunctionBody(),
  3412. GetInlineCache(playout->inlineCacheIndex),
  3413. playout->inlineCacheIndex,
  3414. instance,
  3415. propertyId
  3416. );
  3417. SetReg(playout->Value, value);
  3418. #ifdef TELEMETRY_INTERPRETER
  3419. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3420. {
  3421. // `successful` will be true as PatchGetRootValue throws an exception if not found.
  3422. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, /*successful:*/true);
  3423. }
  3424. #endif
  3425. }
  3426. template <class T>
  3427. void InterpreterStackFrame::OP_GetProperty(unaligned T* playout)
  3428. {
  3429. // Same fast path as in the backend.
  3430. Var instance = GetReg(playout->Instance);
  3431. OP_GetProperty(instance, playout);
  3432. }
  3433. template <class T>
  3434. void InterpreterStackFrame::OP_GetLocalProperty(unaligned T* playout)
  3435. {
  3436. // Same fast path as in the backend.
  3437. Var instance = this->localClosure;
  3438. OP_GetProperty(instance, playout);
  3439. }
  3440. template <class T>
  3441. void InterpreterStackFrame::OP_GetProperty(Var instance, unaligned T* playout)
  3442. {
  3443. InlineCache *inlineCache = GetInlineCache(playout->inlineCacheIndex);
  3444. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3445. if (RecyclableObject::Is(instance))
  3446. {
  3447. RecyclableObject* obj = RecyclableObject::FromVar(instance);
  3448. PropertyValueInfo info;
  3449. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3450. Var value;
  3451. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3452. obj, false, obj, propertyId, &value, GetScriptContext(), nullptr, &info))
  3453. {
  3454. SetReg(playout->Value, value);
  3455. return;
  3456. }
  3457. }
  3458. OP_GetProperty_NoFastPath(instance, playout);
  3459. }
  3460. template <class T>
  3461. void InterpreterStackFrame::OP_GetSuperProperty(unaligned T* playout)
  3462. {
  3463. // Same fast path as in the backend.
  3464. Var instance = GetReg(playout->Instance);
  3465. Var thisInstance = GetReg(playout->Value2);
  3466. InlineCache *inlineCache = GetInlineCache(playout->PropertyIdIndex);
  3467. PropertyId propertyId = GetPropertyIdFromCacheId(playout->PropertyIdIndex);
  3468. if (RecyclableObject::Is(instance) && RecyclableObject::Is(thisInstance))
  3469. {
  3470. RecyclableObject* superObj = RecyclableObject::FromVar(instance);
  3471. RecyclableObject* thisObj = RecyclableObject::FromVar(thisInstance);
  3472. PropertyValueInfo info;
  3473. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->PropertyIdIndex, true);
  3474. Var value;
  3475. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3476. thisObj, false, superObj, propertyId, &value, GetScriptContext(), nullptr, &info))
  3477. {
  3478. SetReg(playout->Value, value);
  3479. return;
  3480. }
  3481. }
  3482. SetReg(
  3483. playout->Value,
  3484. JavascriptOperators::PatchGetValueWithThisPtr<false>(
  3485. GetFunctionBody(),
  3486. GetInlineCache(playout->PropertyIdIndex),
  3487. playout->PropertyIdIndex,
  3488. GetReg(playout->Instance),
  3489. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  3490. GetReg(playout->Value2)));
  3491. }
  3492. template <class T>
  3493. __declspec(noinline) void InterpreterStackFrame::OP_GetProperty_NoFastPath(Var instance, unaligned T* playout)
  3494. {
  3495. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3496. Var value = JavascriptOperators::PatchGetValue<false>(
  3497. GetFunctionBody(),
  3498. GetInlineCache(playout->inlineCacheIndex),
  3499. playout->inlineCacheIndex,
  3500. instance,
  3501. propertyId
  3502. );
  3503. #ifdef TELEMETRY_INTERPRETER
  3504. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3505. {
  3506. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3507. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, true);
  3508. }
  3509. #endif
  3510. SetReg(playout->Value, value);
  3511. }
  3512. #if ENABLE_PROFILE_INFO
  3513. template <class T>
  3514. void InterpreterStackFrame::OP_ProfiledGetProperty(unaligned T* playout)
  3515. {
  3516. ProfiledGetProperty<T, false, false, false>(playout, GetReg(playout->Instance));
  3517. }
  3518. template <class T>
  3519. void InterpreterStackFrame::OP_ProfiledGetLocalProperty(unaligned T* playout)
  3520. {
  3521. ProfiledGetProperty<T, false, false, false>(playout, this->localClosure);
  3522. }
  3523. template <class T>
  3524. void InterpreterStackFrame::OP_ProfiledGetSuperProperty(unaligned T* playout)
  3525. {
  3526. SetReg(
  3527. playout->Value,
  3528. ProfilingHelpers::ProfiledLdFld<false, false, false>(
  3529. GetReg(playout->Instance),
  3530. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  3531. GetInlineCache(playout->PropertyIdIndex),
  3532. playout->PropertyIdIndex,
  3533. GetFunctionBody(),
  3534. GetReg(playout->Value2)));
  3535. }
  3536. template <class T>
  3537. void InterpreterStackFrame::OP_ProfiledGetPropertyForTypeOf(unaligned T* playout)
  3538. {
  3539. Var instance = GetReg(playout->Instance);
  3540. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3541. Var value = ProfilingHelpers::ProfiledLdFldForTypeOf<false, false, false>(
  3542. instance,
  3543. propertyId,
  3544. GetInlineCache(playout->inlineCacheIndex),
  3545. playout->inlineCacheIndex,
  3546. GetFunctionBody()
  3547. );
  3548. SetReg(playout->Value, value);
  3549. #ifdef TELEMETRY_INTERPRETER
  3550. if (TELEMETRY_PROPERTY_OPCODE_FILTER(propertyId))
  3551. {
  3552. // `successful` will be true as PatchGetMethod throws an exception if not found.
  3553. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().GetProperty(instance, propertyId, value, true);
  3554. }
  3555. #endif
  3556. }
  3557. template <class T>
  3558. void InterpreterStackFrame::OP_ProfiledGetPropertyCallApplyTarget(unaligned T* playout)
  3559. {
  3560. ProfiledGetProperty<T, false, false, true>(playout, GetReg(playout->Instance));
  3561. }
  3562. #endif
  3563. template <typename T>
  3564. void InterpreterStackFrame::OP_GetPropertyScoped(const unaligned OpLayoutT_ElementP<T>* playout)
  3565. {
  3566. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3567. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3568. threadContext->ClearImplicitCallFlags();
  3569. // Get the property, using a scope stack rather than an individual instance.
  3570. // Use the cache
  3571. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3572. FrameDisplay *pScope = this->GetEnvForEvalCode();
  3573. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3574. ScriptContext* scriptContext = GetScriptContext();
  3575. int length = pScope->GetLength();
  3576. if ( 1 == length )
  3577. {
  3578. DynamicObject *obj = (DynamicObject*)pScope->GetItem(0);
  3579. PropertyValueInfo info;
  3580. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3581. Var value;
  3582. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3583. obj, false, obj, propertyId, &value, scriptContext, nullptr, &info))
  3584. {
  3585. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3586. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3587. SetReg(playout->Value, value);
  3588. return;
  3589. }
  3590. }
  3591. OP_GetPropertyScoped_NoFastPath(playout);
  3592. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3593. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3594. }
  3595. template <typename T>
  3596. void InterpreterStackFrame::OP_GetPropertyForTypeOfScoped(const unaligned OpLayoutT_ElementP<T>* playout)
  3597. {
  3598. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3599. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3600. threadContext->ClearImplicitCallFlags();
  3601. // Get the property, using a scope stack rather than an individual instance.
  3602. // Use the cache
  3603. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3604. FrameDisplay *pScope = this->GetEnvForEvalCode();
  3605. InlineCache *inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3606. ScriptContext* scriptContext = GetScriptContext();
  3607. int length = pScope->GetLength();
  3608. if (1 == length)
  3609. {
  3610. DynamicObject *obj = (DynamicObject*)pScope->GetItem(0);
  3611. PropertyValueInfo info;
  3612. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3613. Var value;
  3614. if (CacheOperators::TryGetProperty<true, false, false, false, false, false, true, false, false>(
  3615. obj, false, obj, propertyId, &value, scriptContext, nullptr, &info))
  3616. {
  3617. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3618. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3619. SetReg(playout->Value, value);
  3620. return;
  3621. }
  3622. }
  3623. SetReg(
  3624. playout->Value,
  3625. JavascriptOperators::PatchGetPropertyForTypeOfScoped<false>(
  3626. GetFunctionBody(),
  3627. GetInlineCache(playout->inlineCacheIndex),
  3628. playout->inlineCacheIndex,
  3629. GetEnvForEvalCode(),
  3630. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3631. GetReg(Js::FunctionBody::RootObjectRegSlot)));
  3632. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3633. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3634. }
  3635. template <typename T>
  3636. __declspec(noinline) void InterpreterStackFrame::OP_GetPropertyScoped_NoFastPath(const unaligned OpLayoutT_ElementP<T>* playout)
  3637. {
  3638. // Implicit root object as default instance
  3639. Var defaultInstance = GetReg(Js::FunctionBody::RootObjectRegSlot);
  3640. // PatchGetPropertyScoped doesn't update type and slotIndex if the scope is not an array of length 1.
  3641. SetReg(
  3642. playout->Value,
  3643. JavascriptOperators::PatchGetPropertyScoped<false>(
  3644. GetFunctionBody(),
  3645. GetInlineCache(playout->inlineCacheIndex),
  3646. playout->inlineCacheIndex,
  3647. GetEnvForEvalCode(),
  3648. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3649. defaultInstance));
  3650. }
  3651. template <class T>
  3652. void InterpreterStackFrame::OP_SetPropertyScoped(unaligned T* playout, PropertyOperationFlags flags)
  3653. {
  3654. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  3655. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  3656. threadContext->ClearImplicitCallFlags();
  3657. // Set the property, using a scope stack rather than an individual instance.
  3658. // Use the cache
  3659. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3660. FrameDisplay *pScope = this->GetEnvForEvalCode();
  3661. InlineCache *inlineCache = GetInlineCache(playout->inlineCacheIndex);
  3662. ScriptContext* scriptContext = GetScriptContext();
  3663. Var value = GetReg(playout->Value);
  3664. DynamicObject *obj;
  3665. int length = pScope->GetLength();
  3666. if ( 1 == length )
  3667. {
  3668. obj = (DynamicObject*)pScope->GetItem(0);
  3669. PropertyValueInfo info;
  3670. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3671. if (CacheOperators::TrySetProperty<true, false, false, false, false, true, false, false>(
  3672. obj, false, propertyId, value, scriptContext, flags, nullptr, &info))
  3673. {
  3674. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3675. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3676. return;
  3677. }
  3678. }
  3679. OP_SetPropertyScoped_NoFastPath(playout, flags);
  3680. threadContext->CheckAndResetImplicitCallAccessorFlag();
  3681. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  3682. }
  3683. template <class T>
  3684. __declspec(noinline) void InterpreterStackFrame::OP_SetPropertyScoped_NoFastPath(unaligned T* playout, PropertyOperationFlags flags)
  3685. {
  3686. // Implicit root object as default instance
  3687. Var defaultInstance = GetReg(Js::FunctionBody::RootObjectRegSlot);
  3688. // PatchSetPropertyScoped doesn't update type and slotIndex if the scope is not an array of length 1.
  3689. JavascriptOperators::PatchSetPropertyScoped<false>(
  3690. GetFunctionBody(),
  3691. GetInlineCache(playout->inlineCacheIndex),
  3692. playout->inlineCacheIndex,
  3693. GetEnvForEvalCode(),
  3694. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3695. GetReg(playout->Value),
  3696. defaultInstance,
  3697. flags);
  3698. }
  3699. template <class T>
  3700. void InterpreterStackFrame::OP_SetPropertyScopedStrict(unaligned T* playout)
  3701. {
  3702. OP_SetPropertyScoped(playout, PropertyOperation_StrictMode);
  3703. }
  3704. template <class T>
  3705. void InterpreterStackFrame::OP_ConsoleSetPropertyScoped(unaligned T* playout)
  3706. {
  3707. OP_SetPropertyScoped(playout, PropertyOperation_AllowUndeclInConsoleScope);
  3708. }
  3709. template <class T>
  3710. __inline bool InterpreterStackFrame::TrySetPropertyLocalFastPath(unaligned T* playout, PropertyId pid, Var instance, InlineCache*& inlineCache, PropertyOperationFlags flags)
  3711. {
  3712. Assert(!TaggedNumber::Is(instance));
  3713. RecyclableObject* obj = RecyclableObject::FromVar(instance);
  3714. inlineCache = this->GetInlineCache(playout->inlineCacheIndex);
  3715. PropertyValueInfo info;
  3716. PropertyValueInfo::SetCacheInfo(&info, GetFunctionBody(), inlineCache, playout->inlineCacheIndex, true);
  3717. return
  3718. CacheOperators::TrySetProperty<true, false, false, false, false, true, false, false>(
  3719. obj,
  3720. !!(flags & PropertyOperation_Root),
  3721. pid,
  3722. GetReg(playout->Value),
  3723. GetScriptContext(),
  3724. flags,
  3725. nullptr,
  3726. &info);
  3727. }
  3728. template <class T>
  3729. __inline void InterpreterStackFrame::DoSetProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  3730. {
  3731. // Same fast path as in the backend.
  3732. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3733. InlineCache *inlineCache;
  3734. if (!TaggedNumber::Is(instance)
  3735. && TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  3736. {
  3737. if(GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
  3738. {
  3739. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  3740. // function object's constructor cache will be updated with the type produced by the constructor. From that
  3741. // point on, when the same function object is used as a constructor, the a new object with the final type will
  3742. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  3743. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  3744. inlineCache->Clear();
  3745. }
  3746. return;
  3747. }
  3748. DoSetProperty_NoFastPath(playout, instance, flags);
  3749. }
  3750. template <class T>
  3751. __inline void InterpreterStackFrame::DoSetSuperProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  3752. {
  3753. DoSetSuperProperty_NoFastPath(playout, instance, flags);
  3754. }
  3755. template <class T>
  3756. __declspec(noinline) void InterpreterStackFrame::DoSetProperty_NoFastPath(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  3757. {
  3758. #if ENABLE_COPYONACCESS_ARRAY
  3759. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  3760. #endif
  3761. InlineCache *const inlineCache = GetInlineCache(playout->inlineCacheIndex);
  3762. const auto PatchPutRootValue = &JavascriptOperators::PatchPutRootValueNoLocalFastPath<false, InlineCache>;
  3763. const auto PatchPutValue = &JavascriptOperators::PatchPutValueNoLocalFastPath<false, InlineCache>;
  3764. const auto PatchPut = flags & PropertyOperation_Root ? PatchPutRootValue : PatchPutValue;
  3765. PatchPut(
  3766. GetFunctionBody(),
  3767. inlineCache,
  3768. playout->inlineCacheIndex,
  3769. instance,
  3770. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3771. GetReg(playout->Value),
  3772. flags);
  3773. if(!TaggedNumber::Is(instance) && GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
  3774. {
  3775. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  3776. // function object's constructor cache will be updated with the type produced by the constructor. From that
  3777. // point on, when the same function object is used as a constructor, the a new object with the final type will
  3778. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  3779. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  3780. inlineCache->Clear();
  3781. }
  3782. }
  3783. template <class T>
  3784. __declspec(noinline) void InterpreterStackFrame::DoSetSuperProperty_NoFastPath(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  3785. {
  3786. #if ENABLE_COPYONACCESS_ARRAY
  3787. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  3788. #endif
  3789. InlineCache *const inlineCache = GetInlineCache(playout->PropertyIdIndex);
  3790. JavascriptOperators::PatchPutValueWithThisPtrNoLocalFastPath<false, InlineCache>(
  3791. GetFunctionBody(),
  3792. inlineCache,
  3793. playout->PropertyIdIndex,
  3794. instance,
  3795. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  3796. GetReg(playout->Value),
  3797. GetReg(playout->Value2),
  3798. flags);
  3799. if (!TaggedNumber::Is(instance) && GetJavascriptFunction()->GetConstructorCache()->NeedsUpdateAfterCtor())
  3800. {
  3801. // This function has only 'this' statements and is being used as a constructor. When the constructor exits, the
  3802. // function object's constructor cache will be updated with the type produced by the constructor. From that
  3803. // point on, when the same function object is used as a constructor, the a new object with the final type will
  3804. // be created. Whatever is stored in the inline cache currently will cause cache misses after the constructor
  3805. // cache update. So, just clear it now so that the caches won't be flagged as polymorphic.
  3806. inlineCache->Clear();
  3807. }
  3808. }
  3809. #if ENABLE_PROFILE_INFO
  3810. template <class T, bool Root>
  3811. void InterpreterStackFrame::ProfiledSetProperty(unaligned T* playout, Var instance, PropertyOperationFlags flags)
  3812. {
  3813. Assert(!Root || flags & PropertyOperation_Root);
  3814. ProfilingHelpers::ProfiledStFld<Root>(
  3815. instance,
  3816. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3817. GetInlineCache(playout->inlineCacheIndex),
  3818. playout->inlineCacheIndex,
  3819. GetReg(playout->Value),
  3820. flags,
  3821. GetJavascriptFunction(),
  3822. instance);
  3823. }
  3824. template <class T, bool Root>
  3825. void InterpreterStackFrame::ProfiledSetSuperProperty(unaligned T* playout, Var instance, Var thisInstance, PropertyOperationFlags flags)
  3826. {
  3827. Assert(!Root || flags & PropertyOperation_Root);
  3828. ProfilingHelpers::ProfiledStFld<Root>(
  3829. instance,
  3830. GetPropertyIdFromCacheId(playout->PropertyIdIndex),
  3831. GetInlineCache(playout->PropertyIdIndex),
  3832. playout->PropertyIdIndex,
  3833. GetReg(playout->Value),
  3834. flags,
  3835. GetJavascriptFunction(),
  3836. thisInstance);
  3837. }
  3838. #endif
  3839. template <class T>
  3840. void InterpreterStackFrame::OP_SetProperty(unaligned T* playout)
  3841. {
  3842. DoSetProperty(playout, GetReg(playout->Instance), PropertyOperation_None);
  3843. }
  3844. template <class T>
  3845. void InterpreterStackFrame::OP_SetLocalProperty(unaligned T* playout)
  3846. {
  3847. DoSetProperty(playout, this->localClosure, PropertyOperation_None);
  3848. }
  3849. template <class T>
  3850. void InterpreterStackFrame::OP_SetSuperProperty(unaligned T* playout)
  3851. {
  3852. DoSetSuperProperty(playout, GetReg(playout->Instance), PropertyOperation_None);
  3853. }
  3854. template <class T>
  3855. void InterpreterStackFrame::OP_ProfiledSetProperty(unaligned T* playout)
  3856. {
  3857. ProfiledSetProperty<T, false>(playout, GetReg(playout->Instance), PropertyOperation_None);
  3858. }
  3859. template <class T>
  3860. void InterpreterStackFrame::OP_ProfiledSetLocalProperty(unaligned T* playout)
  3861. {
  3862. ProfiledSetProperty<T, false>(playout, this->localClosure, PropertyOperation_None);
  3863. }
  3864. template <class T>
  3865. void InterpreterStackFrame::OP_ProfiledSetSuperProperty(unaligned T* playout)
  3866. {
  3867. ProfiledSetSuperProperty<T, false>(playout, GetReg(playout->Instance), GetReg(playout->Value2), PropertyOperation_None);
  3868. }
  3869. template <class T>
  3870. void InterpreterStackFrame::OP_SetRootProperty(unaligned T* playout)
  3871. {
  3872. DoSetProperty(playout, this->GetRootObject(), PropertyOperation_Root);
  3873. }
  3874. template <class T>
  3875. void InterpreterStackFrame::OP_ProfiledSetRootProperty(unaligned T* playout)
  3876. {
  3877. ProfiledSetProperty<T, true>(playout, this->GetRootObject(), PropertyOperation_Root);
  3878. }
  3879. template <class T>
  3880. void InterpreterStackFrame::OP_SetPropertyStrict(unaligned T* playout)
  3881. {
  3882. DoSetProperty(playout, GetReg(playout->Instance), PropertyOperation_StrictMode);
  3883. }
  3884. template <class T>
  3885. void InterpreterStackFrame::OP_ProfiledSetPropertyStrict(unaligned T* playout)
  3886. {
  3887. ProfiledSetProperty<T, false>(playout, GetReg(playout->Instance), PropertyOperation_StrictMode);
  3888. }
  3889. template <class T>
  3890. void InterpreterStackFrame::OP_SetRootPropertyStrict(unaligned T* playout)
  3891. {
  3892. DoSetProperty(playout, this->GetRootObject(), PropertyOperation_StrictModeRoot);
  3893. }
  3894. template <class T>
  3895. void InterpreterStackFrame::OP_ProfiledSetRootPropertyStrict(unaligned T* playout)
  3896. {
  3897. ProfiledSetProperty<T, true>(playout, this->GetRootObject(), PropertyOperation_StrictModeRoot);
  3898. }
  3899. #if ENABLE_PROFILE_INFO
  3900. template <bool doProfile>
  3901. Var InterpreterStackFrame::ProfiledDivide(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  3902. {
  3903. Var result = JavascriptMath::Divide(aLeft, aRight,scriptContext);
  3904. if (doProfile)
  3905. {
  3906. Js::FunctionBody* body = this->m_functionBody;
  3907. body->GetDynamicProfileInfo()->RecordDivideResultType(body, profileId, result);
  3908. }
  3909. return result;
  3910. }
  3911. template <bool doProfile>
  3912. Var InterpreterStackFrame::ProfileModulus(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  3913. {
  3914. // If both arguments are TaggedInt, then try to do integer division
  3915. // This case is not handled by the lowerer.
  3916. if (doProfile)
  3917. {
  3918. Js::FunctionBody* body = this->function->GetFunctionBody();
  3919. if(TaggedInt::IsPair(aLeft, aRight))
  3920. {
  3921. int nLeft = TaggedInt::ToInt32(aLeft);
  3922. int nRight = TaggedInt::ToInt32(aRight);
  3923. // nLeft is positive and nRight is +2^i
  3924. // Fast path for Power of 2 divisor
  3925. if (nLeft > 0 && ::Math::IsPow2(nRight))
  3926. {
  3927. body->GetDynamicProfileInfo()->RecordModulusOpType(body, profileId, /*isModByPowerOf2*/ true);
  3928. return TaggedInt::ToVarUnchecked(nLeft & (nRight - 1));
  3929. }
  3930. }
  3931. body->GetDynamicProfileInfo()->RecordModulusOpType(body, profileId, /*isModByPowerOf2*/ false);
  3932. }
  3933. return JavascriptMath::Modulus(aLeft, aRight,scriptContext);
  3934. }
  3935. template <bool doProfile>
  3936. Var InterpreterStackFrame::ProfiledSwitch(Var exp, ProfileId profileId)
  3937. {
  3938. if (doProfile)
  3939. {
  3940. Js::FunctionBody* body = this->m_functionBody;
  3941. body->GetDynamicProfileInfo()->RecordSwitchType(body, profileId, exp);
  3942. }
  3943. return exp;
  3944. }
  3945. #else
  3946. template <bool doProfile>
  3947. Var InterpreterStackFrame::ProfiledDivide(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  3948. {
  3949. Assert(!doProfile);
  3950. return JavascriptMath::Divide(aLeft, aRight, scriptContext);
  3951. }
  3952. template <bool doProfile>
  3953. Var InterpreterStackFrame::ProfileModulus(Var aLeft, Var aRight, ScriptContext* scriptContext, ProfileId profileId)
  3954. {
  3955. Assert(!doProfile);
  3956. return JavascriptMath::Modulus(aLeft, aRight, scriptContext);
  3957. }
  3958. template <bool doProfile>
  3959. Var InterpreterStackFrame::ProfiledSwitch(Var exp, ProfileId profileId)
  3960. {
  3961. Assert(!doProfile);
  3962. return exp;
  3963. }
  3964. #endif
  3965. template <class T>
  3966. void InterpreterStackFrame::DoInitProperty(unaligned T* playout, Var instance)
  3967. {
  3968. // Same fast path as in the backend.
  3969. InlineCache *inlineCache = nullptr;
  3970. Assert(!TaggedNumber::Is(instance));
  3971. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3972. if (TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache))
  3973. {
  3974. return;
  3975. }
  3976. DoInitProperty_NoFastPath(playout, instance);
  3977. }
  3978. template <class T>
  3979. __declspec(noinline) void InterpreterStackFrame::DoInitProperty_NoFastPath(unaligned T* playout, Var instance)
  3980. {
  3981. JavascriptOperators::PatchInitValue<false>(
  3982. GetFunctionBody(),
  3983. GetInlineCache(playout->inlineCacheIndex),
  3984. playout->inlineCacheIndex,
  3985. RecyclableObject::FromVar(instance),
  3986. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  3987. GetReg(playout->Value));
  3988. }
  3989. template <class T>
  3990. void InterpreterStackFrame::OP_InitClassMember(const unaligned T * playout)
  3991. {
  3992. uint inlineCacheIndex = playout->inlineCacheIndex;
  3993. InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
  3994. Var instance = GetReg(playout->Instance);
  3995. PropertyOperationFlags flags = PropertyOperation_None;
  3996. Assert(!TaggedNumber::Is(instance));
  3997. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  3998. if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  3999. {
  4000. JavascriptOperators::OP_InitClassMember(instance, propertyId, GetReg(playout->Value));
  4001. }
  4002. }
  4003. template <class T>
  4004. void InterpreterStackFrame::OP_InitClassMemberGet(const unaligned T * playout)
  4005. {
  4006. JavascriptOperators::OP_InitClassMemberGet(
  4007. GetReg(playout->Instance),
  4008. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  4009. GetReg(playout->Value));
  4010. }
  4011. template <class T>
  4012. void InterpreterStackFrame::OP_InitClassMemberSet(const unaligned T * playout)
  4013. {
  4014. JavascriptOperators::OP_InitClassMemberSet(
  4015. GetReg(playout->Instance),
  4016. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  4017. GetReg(playout->Value));
  4018. }
  4019. template <class T>
  4020. void InterpreterStackFrame::OP_InitClassMemberSetComputedName(const unaligned T * playout)
  4021. {
  4022. JavascriptOperators::OP_InitClassMemberSetComputedName(
  4023. GetReg(playout->Instance),
  4024. GetReg(playout->Element),
  4025. GetReg(playout->Value),
  4026. m_functionBody->GetScriptContext());
  4027. }
  4028. template <class T>
  4029. void InterpreterStackFrame::OP_InitClassMemberGetComputedName(const unaligned T * playout)
  4030. {
  4031. JavascriptOperators::OP_InitClassMemberGetComputedName(
  4032. GetReg(playout->Instance),
  4033. GetReg(playout->Element),
  4034. GetReg(playout->Value),
  4035. m_functionBody->GetScriptContext());
  4036. }
  4037. template <class T>
  4038. void InterpreterStackFrame::OP_InitClassMemberComputedName(const unaligned T * playout)
  4039. {
  4040. JavascriptOperators::OP_InitClassMemberComputedName(
  4041. GetReg(playout->Instance),
  4042. GetReg(playout->Element),
  4043. GetReg(playout->Value),
  4044. m_functionBody->GetScriptContext());
  4045. }
  4046. template <class T>
  4047. void InterpreterStackFrame::DoInitLetFld(const unaligned T * playout, Var instance, PropertyOperationFlags flags)
  4048. {
  4049. uint inlineCacheIndex = playout->inlineCacheIndex;
  4050. InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
  4051. Assert(!TaggedNumber::Is(instance));
  4052. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4053. if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  4054. {
  4055. JavascriptOperators::OP_InitLetProperty(instance, propertyId, GetReg(playout->Value));
  4056. }
  4057. }
  4058. template <class T>
  4059. void InterpreterStackFrame::DoInitConstFld(const unaligned T * playout, Var instance, PropertyOperationFlags flags)
  4060. {
  4061. uint inlineCacheIndex = playout->inlineCacheIndex;
  4062. InlineCache * inlineCache = this->GetInlineCache(inlineCacheIndex);
  4063. Assert(!TaggedNumber::Is(instance));
  4064. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4065. if (!TrySetPropertyLocalFastPath(playout, propertyId, instance, inlineCache, flags))
  4066. {
  4067. JavascriptOperators::OP_InitConstProperty(instance, propertyId, GetReg(playout->Value));
  4068. }
  4069. }
  4070. template <class T>
  4071. void InterpreterStackFrame::OP_InitProperty(unaligned T* playout)
  4072. {
  4073. DoInitProperty(playout, GetReg(playout->Instance));
  4074. }
  4075. template <class T>
  4076. void InterpreterStackFrame::OP_InitLocalProperty(unaligned T* playout)
  4077. {
  4078. DoInitProperty(playout, this->localClosure);
  4079. }
  4080. template <class T>
  4081. void InterpreterStackFrame::OP_InitInnerFld(const unaligned T* playout)
  4082. {
  4083. DoInitProperty(playout, InnerScopeFromIndex(playout->scopeIndex));
  4084. }
  4085. template <class T>
  4086. void InterpreterStackFrame::OP_InitLetFld(const unaligned T * playout)
  4087. {
  4088. DoInitLetFld(playout, GetReg(playout->Instance));
  4089. }
  4090. template <class T>
  4091. void InterpreterStackFrame::OP_InitInnerLetFld(const unaligned T * playout)
  4092. {
  4093. DoInitLetFld(playout, InnerScopeFromIndex(playout->scopeIndex));
  4094. }
  4095. template <class T>
  4096. void InterpreterStackFrame::OP_InitLocalLetFld(const unaligned T * playout)
  4097. {
  4098. DoInitLetFld(playout, this->localClosure);
  4099. }
  4100. template <class T>
  4101. void InterpreterStackFrame::OP_InitConstFld(const unaligned T * playout)
  4102. {
  4103. DoInitConstFld(playout, GetReg(playout->Instance));
  4104. }
  4105. template <class T>
  4106. void InterpreterStackFrame::OP_InitRootProperty(unaligned T* playout)
  4107. {
  4108. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  4109. DoInitProperty(playout, this->GetRootObject());
  4110. }
  4111. template <class T>
  4112. void InterpreterStackFrame::OP_InitRootLetFld(const unaligned T * playout)
  4113. {
  4114. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  4115. DoInitLetFld(playout, this->GetRootObject(), PropertyOperation_Root);
  4116. }
  4117. template <class T>
  4118. void InterpreterStackFrame::OP_InitRootConstFld(const unaligned T * playout)
  4119. {
  4120. Assert(playout->inlineCacheIndex >= this->m_functionBody->GetRootObjectLoadInlineCacheStart());
  4121. DoInitConstFld(playout, this->GetRootObject(), PropertyOperation_Root);
  4122. }
  4123. template <class T>
  4124. void InterpreterStackFrame::OP_InitUndeclLetProperty(unaligned T* playout)
  4125. {
  4126. Var instance = InnerScopeFromIndex(playout->scopeIndex);
  4127. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4128. JavascriptOperators::OP_InitLetProperty(instance, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4129. }
  4130. template <class T>
  4131. void InterpreterStackFrame::OP_InitUndeclLocalLetProperty(unaligned T* playout)
  4132. {
  4133. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4134. JavascriptOperators::OP_InitLetProperty(this->localClosure, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4135. }
  4136. void InterpreterStackFrame::OP_InitUndeclRootLetProperty(uint propertyIdIndex)
  4137. {
  4138. Var instance = this->GetRootObject();
  4139. PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
  4140. JavascriptOperators::OP_InitUndeclRootLetProperty(instance, propertyId);
  4141. }
  4142. template <class T>
  4143. void InterpreterStackFrame::OP_InitUndeclConstProperty(unaligned T* playout)
  4144. {
  4145. Var instance = InnerScopeFromIndex(playout->scopeIndex);
  4146. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4147. JavascriptOperators::OP_InitConstProperty(instance, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4148. }
  4149. template <class T>
  4150. void InterpreterStackFrame::OP_InitUndeclLocalConstProperty(unaligned T* playout)
  4151. {
  4152. PropertyId propertyId = GetPropertyIdFromCacheId(playout->inlineCacheIndex);
  4153. JavascriptOperators::OP_InitConstProperty(this->localClosure, propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4154. }
  4155. void InterpreterStackFrame::OP_InitUndeclRootConstProperty(uint propertyIdIndex)
  4156. {
  4157. Var instance = this->GetRootObject();
  4158. PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
  4159. JavascriptOperators::OP_InitUndeclRootConstProperty(instance, propertyId);
  4160. }
  4161. template <class T>
  4162. void InterpreterStackFrame::OP_InitUndeclConsoleLetProperty(unaligned T* playout)
  4163. {
  4164. FrameDisplay* pScope = (FrameDisplay*)this->LdEnv();
  4165. AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
  4166. PropertyId propertyId = m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex);
  4167. JavascriptOperators::OP_InitLetProperty(pScope->GetItem(0), propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4168. }
  4169. template <class T>
  4170. void InterpreterStackFrame::OP_InitUndeclConsoleConstProperty(unaligned T* playout)
  4171. {
  4172. FrameDisplay* pScope = (FrameDisplay*)this->LdEnv();
  4173. AssertMsg(ConsoleScopeActivationObject::Is((DynamicObject*)pScope->GetItem(pScope->GetLength() - 1)), "How come we got this opcode without ConsoleScopeActivationObject?");
  4174. PropertyId propertyId = m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex);
  4175. JavascriptOperators::OP_InitConstProperty(pScope->GetItem(0), propertyId, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  4176. }
  4177. #if ENABLE_PROFILE_INFO
  4178. template <class T>
  4179. void InterpreterStackFrame::ProfiledInitProperty(unaligned T* playout, Var instance)
  4180. {
  4181. ProfilingHelpers::ProfiledInitFld(
  4182. RecyclableObject::FromVar(instance),
  4183. GetPropertyIdFromCacheId(playout->inlineCacheIndex),
  4184. GetInlineCache(playout->inlineCacheIndex),
  4185. playout->inlineCacheIndex,
  4186. GetReg(playout->Value),
  4187. GetFunctionBody());
  4188. }
  4189. template <class T>
  4190. void InterpreterStackFrame::OP_ProfiledInitProperty(unaligned T* playout)
  4191. {
  4192. ProfiledInitProperty(playout, GetReg(playout->Instance));
  4193. }
  4194. template <class T>
  4195. void InterpreterStackFrame::OP_ProfiledInitLocalProperty(unaligned T* playout)
  4196. {
  4197. ProfiledInitProperty(playout, this->localClosure);
  4198. }
  4199. template <class T>
  4200. void InterpreterStackFrame::OP_ProfiledInitRootProperty(unaligned T* playout)
  4201. {
  4202. ProfiledInitProperty(playout, this->GetRootObject());
  4203. }
  4204. template <class T>
  4205. void InterpreterStackFrame::OP_ProfiledGetElementI(const unaligned OpLayoutDynamicProfile<T>* playout)
  4206. {
  4207. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4208. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4209. threadContext->ClearImplicitCallFlags();
  4210. SetReg(
  4211. playout->Value,
  4212. ProfilingHelpers::ProfiledLdElem(
  4213. GetReg(playout->Instance),
  4214. GetReg(playout->Element),
  4215. m_functionBody,
  4216. playout->profileId));
  4217. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4218. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4219. }
  4220. #endif
  4221. template <typename T>
  4222. void InterpreterStackFrame::OP_GetElementI(const unaligned T* playout)
  4223. {
  4224. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4225. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4226. threadContext->ClearImplicitCallFlags();
  4227. // Same fast path as in the backend.
  4228. Var instance = GetReg(playout->Instance);
  4229. // Only enable fast path if the javascript array is not cross site
  4230. Var element;
  4231. #if ENABLE_PROFILE_INFO
  4232. if (!TaggedNumber::Is(instance) && VirtualTableInfo<JavascriptArray>::HasVirtualTable(instance))
  4233. {
  4234. element =
  4235. ProfilingHelpers::ProfiledLdElem_FastPath(
  4236. JavascriptArray::FromVar(instance),
  4237. GetReg(playout->Element),
  4238. GetScriptContext());
  4239. }
  4240. else
  4241. #endif
  4242. {
  4243. element = JavascriptOperators::OP_GetElementI(instance, GetReg(playout->Element), GetScriptContext());
  4244. }
  4245. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4246. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4247. SetReg(playout->Value, element);
  4248. }
  4249. template <typename T>
  4250. void InterpreterStackFrame::OP_SetElementI(const unaligned T* playout, PropertyOperationFlags flags)
  4251. {
  4252. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4253. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4254. threadContext->ClearImplicitCallFlags();
  4255. // Same fast path as in the backend.
  4256. Var instance = GetReg(playout->Instance);
  4257. const Var varIndex = GetReg(playout->Element);
  4258. const Var value = GetReg(playout->Value);
  4259. #if ENABLE_PROFILE_INFO
  4260. // Only enable fast path if the javascript array is not cross site
  4261. if (!TaggedNumber::Is(instance) &&
  4262. VirtualTableInfo<JavascriptArray>::HasVirtualTable(instance) &&
  4263. !JavascriptOperators::SetElementMayHaveImplicitCalls(GetScriptContext()))
  4264. {
  4265. ProfilingHelpers::ProfiledStElem_FastPath(
  4266. JavascriptArray::FromVar(instance),
  4267. varIndex,
  4268. value,
  4269. GetScriptContext(),
  4270. flags);
  4271. }
  4272. else
  4273. #endif
  4274. {
  4275. JavascriptOperators::OP_SetElementI(instance, varIndex, value, GetScriptContext(), flags);
  4276. }
  4277. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4278. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4279. }
  4280. #if ENABLE_PROFILE_INFO
  4281. template <typename T>
  4282. void InterpreterStackFrame::OP_ProfiledSetElementI(
  4283. const unaligned OpLayoutDynamicProfile<T>* playout,
  4284. PropertyOperationFlags flags)
  4285. {
  4286. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4287. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4288. threadContext->ClearImplicitCallFlags();
  4289. ProfilingHelpers::ProfiledStElem(
  4290. GetReg(playout->Instance),
  4291. GetReg(playout->Element),
  4292. GetReg(playout->Value),
  4293. m_functionBody,
  4294. playout->profileId,
  4295. flags);
  4296. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4297. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4298. }
  4299. #endif
  4300. template <typename T>
  4301. void InterpreterStackFrame::OP_SetElementIStrict(const unaligned T* playout)
  4302. {
  4303. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4304. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4305. threadContext->ClearImplicitCallFlags();
  4306. OP_SetElementI(playout, PropertyOperation_StrictMode);
  4307. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4308. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4309. }
  4310. #if ENABLE_PROFILE_INFO
  4311. template <typename T>
  4312. void InterpreterStackFrame::OP_ProfiledSetElementIStrict(const unaligned OpLayoutDynamicProfile<T>* playout)
  4313. {
  4314. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  4315. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  4316. threadContext->ClearImplicitCallFlags();
  4317. OP_ProfiledSetElementI(playout, PropertyOperation_StrictMode);
  4318. threadContext->CheckAndResetImplicitCallAccessorFlag();
  4319. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  4320. }
  4321. #endif
  4322. template <class T>
  4323. void InterpreterStackFrame::OP_LdArrayHeadSegment(const unaligned T* playout)
  4324. {
  4325. JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->R1));
  4326. // The array is create by the built-in on the same script context
  4327. Assert(array->GetScriptContext() == GetScriptContext());
  4328. SetNonVarReg(playout->R0, array->GetHead());
  4329. }
  4330. template <class T>
  4331. void InterpreterStackFrame::OP_SetArraySegmentItem_CI4(const unaligned T* playout)
  4332. {
  4333. SparseArraySegment<Var> * segment = (SparseArraySegment<Var> *)GetNonVarReg(playout->Instance);
  4334. uint32 index = playout->Element;
  4335. Var value = GetReg(playout->Value);
  4336. Assert(segment->left == 0);
  4337. Assert(index < segment->length);
  4338. segment->elements[index] = value;
  4339. }
  4340. template <class T>
  4341. void InterpreterStackFrame::OP_NewScArray(const unaligned T * playout)
  4342. {
  4343. JavascriptArray *arr;
  4344. arr = scriptContext->GetLibrary()->CreateArrayLiteral(playout->C1);
  4345. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4346. arr->CheckForceES5Array();
  4347. #endif
  4348. SetReg(playout->R0, arr);
  4349. }
  4350. #if ENABLE_PROFILE_INFO
  4351. template <bool Profiled, class T>
  4352. void InterpreterStackFrame::ProfiledNewScArray(const unaligned OpLayoutDynamicProfile<T> * playout)
  4353. {
  4354. if(!Profiled && !isAutoProfiling)
  4355. {
  4356. OP_NewScArray(playout);
  4357. return;
  4358. }
  4359. SetReg(
  4360. playout->R0,
  4361. ProfilingHelpers::ProfiledNewScArray(
  4362. playout->C1,
  4363. m_functionBody,
  4364. playout->profileId));
  4365. }
  4366. #else
  4367. template <bool Profiled, class T>
  4368. void InterpreterStackFrame::ProfiledNewScArray(const unaligned OpLayoutDynamicProfile<T> * playout)
  4369. {
  4370. Assert(!Profiled);
  4371. OP_NewScArray(playout);
  4372. }
  4373. #endif
  4374. void InterpreterStackFrame::OP_NewScIntArray(const unaligned OpLayoutAuxiliary * playout)
  4375. {
  4376. #if ENABLE_PROFILE_INFO
  4377. if(isAutoProfiling)
  4378. {
  4379. OP_ProfiledNewScIntArray(static_cast<const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> *>(playout));
  4380. return;
  4381. }
  4382. #endif
  4383. const Js::AuxArray<int32> *ints = Js::ByteCodeReader::ReadAuxArray<int32>(playout->Offset, this->GetFunctionBody());
  4384. JavascriptNativeIntArray *arr = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(ints->count);
  4385. SparseArraySegment<int32> * segment = (SparseArraySegment<int32>*)arr->GetHead();
  4386. JavascriptOperators::AddIntsToArraySegment(segment, ints);
  4387. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4388. arr->CheckForceES5Array();
  4389. #endif
  4390. SetReg(playout->R0, arr);
  4391. }
  4392. #if ENABLE_PROFILE_INFO
  4393. void InterpreterStackFrame::OP_ProfiledNewScIntArray(const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> * playout)
  4394. {
  4395. const Js::AuxArray<int32> *ints = Js::ByteCodeReader::ReadAuxArray<int32>(playout->Offset, this->GetFunctionBody());
  4396. Js::ProfileId profileId = playout->profileId;
  4397. FunctionBody *functionBody = this->m_functionBody;
  4398. ArrayCallSiteInfo *arrayInfo = functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
  4399. Assert(arrayInfo);
  4400. JavascriptArray *arr;
  4401. JavascriptLibrary *lib = scriptContext->GetLibrary();
  4402. if (arrayInfo && arrayInfo->IsNativeIntArray())
  4403. {
  4404. #if ENABLE_COPYONACCESS_ARRAY
  4405. if (JavascriptLibrary::IsCopyOnAccessArrayCallSite(lib, arrayInfo, ints->count))
  4406. {
  4407. Assert(lib->cacheForCopyOnAccessArraySegments);
  4408. arr = scriptContext->GetLibrary()->CreateCopyOnAccessNativeIntArrayLiteral(arrayInfo, functionBody, ints);
  4409. }
  4410. else
  4411. #endif
  4412. {
  4413. arr = scriptContext->GetLibrary()->CreateNativeIntArrayLiteral(ints->count);
  4414. SparseArraySegment<int32> *segment = (SparseArraySegment<int32>*)arr->GetHead();
  4415. JavascriptOperators::AddIntsToArraySegment(segment, ints);
  4416. }
  4417. JavascriptNativeIntArray *intArray = reinterpret_cast<JavascriptNativeIntArray*>(arr);
  4418. Recycler *recycler = scriptContext->GetRecycler();
  4419. intArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  4420. }
  4421. else if (arrayInfo && arrayInfo->IsNativeFloatArray())
  4422. {
  4423. arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(ints->count);
  4424. SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
  4425. for (uint i = 0; i < ints->count; i++)
  4426. {
  4427. segment->elements[i] = (double)ints->elements[i];
  4428. }
  4429. JavascriptNativeFloatArray *floatArray = reinterpret_cast<JavascriptNativeFloatArray*>(arr);
  4430. Recycler *recycler = scriptContext->GetRecycler();
  4431. floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  4432. }
  4433. else
  4434. {
  4435. arr = scriptContext->GetLibrary()->CreateArrayLiteral(ints->count);
  4436. SparseArraySegment<Var> * segment = (SparseArraySegment<Var>*)arr->GetHead();
  4437. for (uint i = 0; i < ints->count; i++)
  4438. {
  4439. segment->elements[i] = JavascriptNumber::ToVar(ints->elements[i], scriptContext);
  4440. }
  4441. }
  4442. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4443. arr->CheckForceES5Array();
  4444. #endif
  4445. SetReg(playout->R0, arr);
  4446. }
  4447. #endif
  4448. void InterpreterStackFrame::OP_NewScFltArray(const unaligned OpLayoutAuxiliary * playout )
  4449. {
  4450. #if ENABLE_PROFILE_INFO
  4451. if(isAutoProfiling)
  4452. {
  4453. OP_ProfiledNewScFltArray(static_cast<const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> *>(playout));
  4454. return;
  4455. }
  4456. #endif
  4457. const Js::AuxArray<double> *doubles = Js::ByteCodeReader::ReadAuxArray<double>(playout->Offset, this->GetFunctionBody());
  4458. JavascriptNativeFloatArray *arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(doubles->count);
  4459. SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
  4460. JavascriptOperators::AddFloatsToArraySegment(segment, doubles);
  4461. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4462. arr->CheckForceES5Array();
  4463. #endif
  4464. SetReg(playout->R0, arr);
  4465. }
  4466. #if ENABLE_PROFILE_INFO
  4467. void InterpreterStackFrame::OP_ProfiledNewScFltArray(const unaligned OpLayoutDynamicProfile<OpLayoutAuxiliary> * playout)
  4468. {
  4469. const Js::AuxArray<double> *doubles = Js::ByteCodeReader::ReadAuxArray<double>(playout->Offset, this->GetFunctionBody());
  4470. Js::ProfileId profileId = playout->profileId;
  4471. FunctionBody *functionBody = this->m_functionBody;
  4472. ArrayCallSiteInfo *arrayInfo = functionBody->GetDynamicProfileInfo()->GetArrayCallSiteInfo(functionBody, profileId);
  4473. Assert(arrayInfo);
  4474. JavascriptArray *arr;
  4475. if (arrayInfo && arrayInfo->IsNativeFloatArray())
  4476. {
  4477. arrayInfo->SetIsNotNativeIntArray();
  4478. arr = scriptContext->GetLibrary()->CreateNativeFloatArrayLiteral(doubles->count);
  4479. SparseArraySegment<double> * segment = (SparseArraySegment<double>*)arr->GetHead();
  4480. JavascriptOperators::AddFloatsToArraySegment(segment, doubles);
  4481. JavascriptNativeFloatArray *floatArray = reinterpret_cast<JavascriptNativeFloatArray*>(arr);
  4482. Recycler *recycler = scriptContext->GetRecycler();
  4483. floatArray->SetArrayCallSite(profileId, recycler->CreateWeakReferenceHandle(functionBody));
  4484. }
  4485. else
  4486. {
  4487. arr = scriptContext->GetLibrary()->CreateArrayLiteral(doubles->count);
  4488. SparseArraySegment<Var> * segment = (SparseArraySegment<Var>*)arr->GetHead();
  4489. for (uint i = 0; i < doubles->count; i++)
  4490. {
  4491. segment->elements[i] = JavascriptNumber::ToVarNoCheck(doubles->elements[i], scriptContext);
  4492. }
  4493. }
  4494. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  4495. arr->CheckForceES5Array();
  4496. #endif
  4497. SetReg(playout->R0, arr);
  4498. }
  4499. #endif
  4500. void InterpreterStackFrame::OP_SetArraySegmentVars(const unaligned OpLayoutAuxiliary * playout)
  4501. {
  4502. const Js::VarArray *vars = Js::ByteCodeReader::ReadAuxArray<Var>(playout->Offset, this->GetFunctionBody());
  4503. SparseArraySegment<Var> * segment =(SparseArraySegment<Var> *)GetNonVarReg(playout->R0);
  4504. JavascriptOperators::AddVarsToArraySegment(segment, vars);
  4505. }
  4506. template <class T>
  4507. void InterpreterStackFrame::OP_SetArrayItemC_CI4(const unaligned T* playout)
  4508. {
  4509. JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->Instance));
  4510. uint32 index = playout->Element;
  4511. Var value = GetReg(playout->Value);
  4512. #if ENABLE_COPYONACCESS_ARRAY
  4513. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(value);
  4514. #endif
  4515. // The array is create by the built-in on the same script context
  4516. Assert(array->GetScriptContext() == GetScriptContext());
  4517. TypeId typeId = array->GetTypeId();
  4518. if (typeId == TypeIds_NativeIntArray)
  4519. {
  4520. JavascriptArray::OP_SetNativeIntElementC(reinterpret_cast<JavascriptNativeIntArray*>(array), index, value, array->GetScriptContext());
  4521. }
  4522. else if (typeId == TypeIds_NativeFloatArray)
  4523. {
  4524. JavascriptArray::OP_SetNativeFloatElementC(reinterpret_cast<JavascriptNativeFloatArray*>(array), index, value, array->GetScriptContext());
  4525. }
  4526. else
  4527. {
  4528. array->SetArrayLiteralItem(index, value);
  4529. }
  4530. }
  4531. template <class T>
  4532. void InterpreterStackFrame::OP_SetArrayItemI_CI4(const unaligned T* playout)
  4533. {
  4534. // Note that this code assumes that we only get here when we see an array literal,
  4535. // so we know that the instance is truly an array, and the index is a uint32.
  4536. // If/when we use this for cases like "a[0] = x", we'll at least have to check
  4537. // whether "a" is really an array.
  4538. JavascriptArray* array = JavascriptArray::FromAnyArray(GetReg(playout->Instance));
  4539. // The array is create by the built-in on the same script context
  4540. Assert(array->GetScriptContext() == GetScriptContext());
  4541. uint32 index = playout->Element;
  4542. Var value = GetReg(playout->Value);
  4543. Assert(VirtualTableInfo<JavascriptArray>::HasVirtualTable(array));
  4544. SparseArraySegment<Var>* lastUsedSeg = (SparseArraySegment<Var>*)array->GetLastUsedSegment();
  4545. if (index < lastUsedSeg->left)
  4546. {
  4547. goto helper;
  4548. }
  4549. uint32 index2 = index - lastUsedSeg->left;
  4550. if (index2 < lastUsedSeg->size)
  4551. {
  4552. // Successful fastpath
  4553. array->DirectSetItemInLastUsedSegmentAt(index2, value);
  4554. return;
  4555. }
  4556. helper:
  4557. ScriptContext* scriptContext = array->GetScriptContext();
  4558. JavascriptOperators::SetItem(array, array, index, value, scriptContext);
  4559. }
  4560. #if ENABLE_PROFILE_INFO
  4561. Var InterpreterStackFrame::OP_ProfiledLdThis(Var thisVar, int moduleID, ScriptContext *scriptContext)
  4562. {
  4563. FunctionBody * functionBody = this->m_functionBody;
  4564. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  4565. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4566. if (JavascriptOperators::IsThisSelf(typeId))
  4567. {
  4568. Assert(typeId != TypeIds_GlobalObject || ((Js::GlobalObject*)thisVar)->ToThis() == thisVar);
  4569. Assert(typeId != TypeIds_ModuleRoot || JavascriptOperators::GetThisFromModuleRoot(thisVar) == thisVar);
  4570. // Record the fact that we saw a trivial LdThis.
  4571. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
  4572. return thisVar;
  4573. }
  4574. thisVar = JavascriptOperators::OP_GetThis(thisVar, moduleID, scriptContext);
  4575. // Record the fact that we saw a LdThis that had to map its source to something else, or at least
  4576. // forced us to call a helper, e.g., a FastDOM object with an unrecognized type ID.
  4577. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
  4578. return thisVar;
  4579. }
  4580. Var InterpreterStackFrame::OP_ProfiledStrictLdThis(Var thisVar, ScriptContext* scriptContext)
  4581. {
  4582. FunctionBody * functionBody = this->m_functionBody;
  4583. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  4584. TypeId typeId = JavascriptOperators::GetTypeId(thisVar);
  4585. if (typeId == TypeIds_ActivationObject)
  4586. {
  4587. thisVar = scriptContext->GetLibrary()->GetUndefined();
  4588. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Mapped);
  4589. return thisVar;
  4590. }
  4591. dynamicProfileInfo->RecordThisInfo(thisVar, ThisType_Simple);
  4592. return thisVar;
  4593. }
  4594. #endif
  4595. void InterpreterStackFrame::OP_InitCachedFuncs(const unaligned OpLayoutAuxNoReg * playout)
  4596. {
  4597. const FuncInfoArray *info = Js::ByteCodeReader::ReadAuxArray<FuncInfoEntry>(playout->Offset, this->GetFunctionBody());
  4598. JavascriptOperators::OP_InitCachedFuncs(this->localClosure, GetLocalFrameDisplay(), info, GetScriptContext());
  4599. }
  4600. Var InterpreterStackFrame::OP_GetCachedFunc(Var instance, int32 index)
  4601. {
  4602. ActivationObjectEx *obj = (ActivationObjectEx*)ActivationObjectEx::FromVar(instance);
  4603. FuncCacheEntry *entry = obj->GetFuncCacheEntry((uint)index);
  4604. return entry->func;
  4605. }
  4606. void InterpreterStackFrame::OP_CommitScope(const unaligned OpLayoutAuxNoReg * playout)
  4607. {
  4608. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4609. this->OP_CommitScopeHelper(playout, propIds);
  4610. }
  4611. void InterpreterStackFrame::OP_CommitScopeHelper(const unaligned OpLayoutAuxNoReg *playout, const PropertyIdArray *propIds)
  4612. {
  4613. ActivationObjectEx *obj = (ActivationObjectEx*)ActivationObjectEx::FromVar(/*GetReg(playout->R0)*/this->localClosure);
  4614. ScriptFunction *func = obj->GetParentFunc();
  4615. Assert(obj->GetParentFunc() == func);
  4616. if (func->GetCachedScope() == obj)
  4617. {
  4618. PropertyId firstVarSlot = ActivationObjectEx::GetFirstVarSlot(propIds);
  4619. Var undef = scriptContext->GetLibrary()->GetUndefined();
  4620. for (uint i = firstVarSlot; i < propIds->count; i++)
  4621. {
  4622. obj->SetSlot(SetSlotArguments(propIds->elements[i], i, undef));
  4623. }
  4624. obj->SetCommit(true);
  4625. }
  4626. }
  4627. Var InterpreterStackFrame::OP_NewScObjectSimple()
  4628. {
  4629. Var object = scriptContext->GetLibrary()->CreateObject(true);
  4630. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(object));
  4631. #if ENABLE_DEBUG_CONFIG_OPTIONS
  4632. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  4633. {
  4634. object = JavascriptProxy::AutoProxyWrapper(object);
  4635. }
  4636. #endif
  4637. return object;
  4638. }
  4639. void InterpreterStackFrame::OP_NewScObjectLiteral(const unaligned OpLayoutAuxiliary * playout )
  4640. {
  4641. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4642. Var newObj = JavascriptOperators::NewScObjectLiteral(GetScriptContext(), propIds,
  4643. this->GetFunctionBody()->GetObjectLiteralTypeRef(playout->C1));
  4644. SetReg(playout->R0, newObj);
  4645. }
  4646. void InterpreterStackFrame::OP_NewScObjectLiteral_LS(const unaligned OpLayoutAuxiliary * playout, RegSlot& target)
  4647. {
  4648. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4649. target = playout->R0;
  4650. Var newObj = JavascriptOperators::NewScObjectLiteral(GetScriptContext(), propIds,
  4651. this->GetFunctionBody()->GetObjectLiteralTypeRef(playout->C1));
  4652. SetReg(playout->R0, newObj);
  4653. target = Js::Constants::NoRegister;
  4654. }
  4655. void InterpreterStackFrame::OP_LdPropIds(const unaligned OpLayoutAuxiliary * playout)
  4656. {
  4657. const Js::PropertyIdArray *propIds = Js::ByteCodeReader::ReadPropertyIdArray(playout->Offset, this->GetFunctionBody());
  4658. SetNonVarReg(playout->R0, (Var)propIds);
  4659. }
  4660. bool InterpreterStackFrame::IsCurrentLoopNativeAddr(void * codeAddr) const
  4661. {
  4662. if (this->GetCurrentLoopNum() == LoopHeader::NoLoop)
  4663. {
  4664. return false;
  4665. }
  4666. // TODO: Do more verification?
  4667. return true;
  4668. }
  4669. #if ENABLE_PROFILE_INFO
  4670. void InterpreterStackFrame::OP_RecordImplicitCall(uint loopNumber)
  4671. {
  4672. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  4673. Assert(loopNumber < this->m_functionBody->GetLoopCount());
  4674. FunctionBody* functionBody = this->m_functionBody;
  4675. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  4676. ThreadContext * threadContext = scriptContext->GetThreadContext();
  4677. dynamicProfileInfo->RecordLoopImplicitCallFlags(functionBody, loopNumber, threadContext->GetImplicitCallFlags());
  4678. }
  4679. template <LayoutSize layoutSize, bool profiled>
  4680. const byte * InterpreterStackFrame::OP_ProfiledLoopStart(const byte * ip)
  4681. {
  4682. const uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4683. if(!profiled && !isAutoProfiling)
  4684. {
  4685. return ip;
  4686. }
  4687. ThreadContext *const threadContext = GetScriptContext()->GetThreadContext();
  4688. threadContext->IncrementLoopDepth();
  4689. // Save the implicit call flags. The interpreter may switch to profiling mode during LoopBodyStart, so always do this.
  4690. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  4691. this->savedLoopImplicitCallFlags[C1] = threadContext->GetImplicitCallFlags();
  4692. threadContext->SetImplicitCallFlags(ImplicitCall_None);
  4693. this->currentLoopCounter = 0;
  4694. if(!profiled)
  4695. {
  4696. return ip;
  4697. }
  4698. LayoutSize localLayoutSize;
  4699. OpCode peekOp = m_reader.PeekOp(ip, localLayoutSize);
  4700. Assert(peekOp != OpCode::LoopBodyStart);
  4701. if (peekOp == OpCode::ProfiledLoopBodyStart)
  4702. {
  4703. Assert(localLayoutSize == layoutSize);
  4704. ip += Js::OpCodeUtil::EncodedSize(peekOp, layoutSize);
  4705. // We are doing JIT loop body. Process the first ProfiledLoopBodyStart to avoid recording
  4706. // the implicit call before the first iteration
  4707. uint32 C2 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4708. Assert(C1 == C2);
  4709. (this->*opProfiledLoopBodyStart)(C1, layoutSize, true /* isFirstIteration */);
  4710. return m_reader.GetIP();
  4711. }
  4712. return ip;
  4713. }
  4714. template <LayoutSize layoutSize, bool profiled>
  4715. const byte * InterpreterStackFrame::OP_ProfiledLoopEnd(const byte * ip)
  4716. {
  4717. uint32 loopNumber = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4718. if(!profiled && !isAutoProfiling)
  4719. {
  4720. return ip;
  4721. }
  4722. this->CheckIfLoopIsHot(this->currentLoopCounter);
  4723. Js::FunctionBody *fn = this->function->GetFunctionBody();
  4724. if (fn->HasDynamicProfileInfo())
  4725. {
  4726. fn->GetAnyDynamicProfileInfo()->SetLoopInterpreted(loopNumber);
  4727. // If the counter is 0, there is a high chance that some config disabled tracking that information. (ie: -off:jitloopbody)
  4728. // Assume it is valid for memop in this case.
  4729. if (this->currentLoopCounter >= (uint)CONFIG_FLAG(MinMemOpCount) ||
  4730. (this->currentLoopCounter == 0 && !this->m_functionBody->DoJITLoopBody())
  4731. )
  4732. {
  4733. // This flag becomes relevant only if the loop has been interpreted
  4734. fn->GetAnyDynamicProfileInfo()->SetMemOpMinReached(loopNumber);
  4735. }
  4736. }
  4737. this->currentLoopCounter = 0;
  4738. if (profiled)
  4739. {
  4740. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  4741. OP_RecordImplicitCall(loopNumber);
  4742. if(switchProfileModeOnLoopEndNumber == loopNumber)
  4743. {
  4744. // Stop profiling since the jitted loop body would be exiting the loop
  4745. Assert(!switchProfileMode);
  4746. switchProfileMode = true;
  4747. switchProfileModeOnLoopEndNumber = 0u - 1;
  4748. }
  4749. }
  4750. // Restore the implicit call flags state and add with flags in the loop as well
  4751. ThreadContext *const threadContext = GetScriptContext()->GetThreadContext();
  4752. threadContext->AddImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
  4753. threadContext->DecrementLoopDepth();
  4754. return ip;
  4755. }
  4756. template <LayoutSize layoutSize, bool profiled>
  4757. const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
  4758. {
  4759. uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4760. if(profiled || isAutoProfiling)
  4761. {
  4762. this->currentLoopCounter++;
  4763. }
  4764. if (profiled)
  4765. {
  4766. OP_RecordImplicitCall(C1);
  4767. }
  4768. (this->*(profiled ? opProfiledLoopBodyStart : opLoopBodyStart))(C1, layoutSize, false /* isFirstIteration */);
  4769. return m_reader.GetIP();
  4770. }
  4771. template<bool InterruptProbe, bool JITLoopBody>
  4772. void InterpreterStackFrame::ProfiledLoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, bool isFirstIteration)
  4773. {
  4774. Assert(Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()));
  4775. if (InterruptProbe)
  4776. {
  4777. this->DoInterruptProbe();
  4778. }
  4779. if (!JITLoopBody || this->IsInCatchOrFinallyBlock())
  4780. {
  4781. // For functions having try-catch-finally, jit loop bodies for loops that are contained only in a try block,
  4782. // not even indirect containment in a Catch or Finally.
  4783. return;
  4784. }
  4785. LoopHeader const * loopHeader = DoLoopBodyStart(loopNumber, layoutSize, false, isFirstIteration);
  4786. Assert(loopHeader == nullptr || this->m_functionBody->GetLoopNumber(loopHeader) == loopNumber);
  4787. if (loopHeader != nullptr)
  4788. {
  4789. // We executed jitted loop body, no implicit call information available for this loop
  4790. uint currentOffset = m_reader.GetCurrentOffset();
  4791. if (!loopHeader->Contains(currentOffset) || (m_reader.PeekOp() == OpCode::ProfiledLoopEnd))
  4792. {
  4793. // Restore the outer loop's implicit call flags
  4794. scriptContext->GetThreadContext()->SetImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
  4795. }
  4796. else
  4797. {
  4798. // We bailout from the loop, just continue collect implicit call flags for this loop
  4799. }
  4800. }
  4801. }
  4802. #else
  4803. template <LayoutSize layoutSize, bool profiled>
  4804. const byte * InterpreterStackFrame::OP_ProfiledLoopStart(const byte * ip)
  4805. {
  4806. Assert(!profiled);
  4807. return ip;
  4808. }
  4809. template <LayoutSize layoutSize, bool profiled>
  4810. const byte * InterpreterStackFrame::OP_ProfiledLoopEnd(const byte * ip)
  4811. {
  4812. Assert(!profiled);
  4813. return ip;
  4814. }
  4815. template <LayoutSize layoutSize, bool profiled>
  4816. const byte * InterpreterStackFrame::OP_ProfiledLoopBodyStart(const byte * ip)
  4817. {
  4818. uint32 C1 = m_reader.GetLayout<OpLayoutT_Unsigned1<LayoutSizePolicy<layoutSize>>>(ip)->C1;
  4819. Assert(!profiled);
  4820. (this->*opLoopBodyStart)(C1, layoutSize, false /* isFirstIteration */);
  4821. return m_reader.GetIP();
  4822. }
  4823. #endif
  4824. template<bool InterruptProbe, bool JITLoopBody>
  4825. void InterpreterStackFrame::LoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, bool isFirstIteration)
  4826. {
  4827. if (InterruptProbe)
  4828. {
  4829. this->DoInterruptProbe();
  4830. }
  4831. if (!JITLoopBody || this->IsInCatchOrFinallyBlock())
  4832. {
  4833. // For functions having try-catch-finally, jit loop bodies for loops that are contained only in a try block,
  4834. // not even indirect containment in a Catch or Finally.
  4835. return;
  4836. }
  4837. DoLoopBodyStart(loopNumber, layoutSize, true, isFirstIteration);
  4838. }
  4839. LoopHeader const * InterpreterStackFrame::DoLoopBodyStart(uint32 loopNumber, LayoutSize layoutSize, const bool doProfileLoopCheck, const bool isFirstIteration)
  4840. {
  4841. #if ENABLE_PROFILE_INFO
  4842. class AutoRestoreLoopNumbers
  4843. {
  4844. private:
  4845. InterpreterStackFrame *const interpreterStackFrame;
  4846. uint32 loopNumber;
  4847. bool doProfileLoopCheck;
  4848. public:
  4849. AutoRestoreLoopNumbers(InterpreterStackFrame *const interpreterStackFrame, uint32 loopNumber, bool doProfileLoopCheck)
  4850. : interpreterStackFrame(interpreterStackFrame), loopNumber(loopNumber), doProfileLoopCheck(doProfileLoopCheck)
  4851. {
  4852. Assert(interpreterStackFrame->currentLoopNum == LoopHeader::NoLoop);
  4853. interpreterStackFrame->currentLoopNum = loopNumber;
  4854. interpreterStackFrame->m_functionBody->SetRecentlyBailedOutOfJittedLoopBody(false);
  4855. }
  4856. ~AutoRestoreLoopNumbers()
  4857. {
  4858. interpreterStackFrame->currentLoopNum = LoopHeader::NoLoop;
  4859. interpreterStackFrame->currentLoopCounter = 0;
  4860. Js::FunctionBody* fn = interpreterStackFrame->m_functionBody;
  4861. if (fn->RecentlyBailedOutOfJittedLoopBody())
  4862. {
  4863. if (doProfileLoopCheck && interpreterStackFrame->isAutoProfiling)
  4864. {
  4865. // Start profiling the loop after a bailout. Some bailouts require subsequent profile data collection such
  4866. // that the rejitted loop body would not bail out again for the same reason.
  4867. Assert(!interpreterStackFrame->switchProfileMode);
  4868. interpreterStackFrame->switchProfileMode = true;
  4869. Assert(interpreterStackFrame->switchProfileModeOnLoopEndNumber == 0u - 1);
  4870. interpreterStackFrame->switchProfileModeOnLoopEndNumber = loopNumber;
  4871. }
  4872. }
  4873. else
  4874. {
  4875. if (interpreterStackFrame->switchProfileModeOnLoopEndNumber == loopNumber)
  4876. {
  4877. // Stop profiling since the jitted loop body would be exiting the loop
  4878. Assert(!interpreterStackFrame->switchProfileMode);
  4879. interpreterStackFrame->switchProfileMode = true;
  4880. interpreterStackFrame->switchProfileModeOnLoopEndNumber = 0u - 1;
  4881. }
  4882. interpreterStackFrame->scriptContext->GetThreadContext()->DecrementLoopDepth();
  4883. }
  4884. }
  4885. };
  4886. #endif
  4887. Js::FunctionBody* fn = this->m_functionBody;
  4888. Assert(loopNumber < fn->GetLoopCount());
  4889. Assert(!this->IsInCatchOrFinallyBlock());
  4890. Js::LoopHeader *loopHeader = fn->GetLoopHeader(loopNumber);
  4891. loopHeader->isInTry = (this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
  4892. Js::LoopEntryPointInfo * entryPointInfo = loopHeader->GetCurrentEntryPointInfo();
  4893. if (fn->ForceJITLoopBody() && loopHeader->interpretCount == 0 &&
  4894. (entryPointInfo != NULL && entryPointInfo->IsNotScheduled()))
  4895. {
  4896. #if ENABLE_PROFILE_INFO
  4897. if (Js::DynamicProfileInfo::EnableImplicitCallFlags(GetFunctionBody()))
  4898. {
  4899. scriptContext->GetThreadContext()->AddImplicitCallFlags(this->savedLoopImplicitCallFlags[loopNumber]);
  4900. }
  4901. #endif
  4902. #if ENABLE_NATIVE_CODEGEN
  4903. GenerateLoopBody(scriptContext->GetNativeCodeGenerator(), fn, loopHeader, entryPointInfo, fn->GetLocalsCount(), this->m_localSlots);
  4904. #endif
  4905. }
  4906. #if ENABLE_NATIVE_CODEGEN
  4907. // If we have JITted the loop, call the JITted code
  4908. if (entryPointInfo != NULL && entryPointInfo->IsCodeGenDone())
  4909. {
  4910. #if DBG_DUMP
  4911. if (PHASE_TRACE1(Js::JITLoopBodyPhase) && CONFIG_FLAG(Verbose))
  4912. {
  4913. fn->DumpFunctionId(true);
  4914. Output::Print(L": %-20s LoopBody Execute Loop: %2d\n", fn->GetDisplayName(), loopNumber);
  4915. Output::Flush();
  4916. }
  4917. loopHeader->nativeCount++;
  4918. #endif
  4919. #ifdef BGJIT_STATS
  4920. entryPointInfo->MarkAsUsed();
  4921. #endif
  4922. entryPointInfo->EnsureIsReadyToCall();
  4923. RegSlot envReg = this->m_functionBody->GetEnvReg();
  4924. if (envReg != Constants::NoRegister)
  4925. {
  4926. this->SetNonVarReg(envReg, this->LdEnv());
  4927. }
  4928. RegSlot localClosureReg = this->m_functionBody->GetLocalClosureReg();
  4929. RegSlot localFrameDisplayReg = this->m_functionBody->GetLocalFrameDisplayReg();
  4930. if (entryPointInfo->HasJittedStackClosure())
  4931. {
  4932. // The jitted code is expecting the closure registers to point to known stack locations where
  4933. // the closures can be found and possibly boxed.
  4934. // In a jitted loop body, those locations are the local closure fields on the interpreter instance.
  4935. if (localClosureReg != Constants::NoRegister)
  4936. {
  4937. this->SetNonVarReg(localClosureReg, &this->localClosure);
  4938. }
  4939. if (localFrameDisplayReg != Constants::NoRegister)
  4940. {
  4941. this->SetNonVarReg(localFrameDisplayReg, &this->localFrameDisplay);
  4942. }
  4943. }
  4944. else
  4945. {
  4946. // In non-stack-closure jitted code, the closure registers are expected to hold the addresses
  4947. // of the actual structures.
  4948. if (localClosureReg != Constants::NoRegister)
  4949. {
  4950. this->SetNonVarReg(localClosureReg, this->localClosure);
  4951. }
  4952. if (localFrameDisplayReg != Constants::NoRegister)
  4953. {
  4954. this->SetNonVarReg(localFrameDisplayReg, this->localFrameDisplay);
  4955. }
  4956. }
  4957. uint32 innerScopeCount = this->m_functionBody->GetInnerScopeCount();
  4958. for (uint32 i = 0; i < innerScopeCount; i++)
  4959. {
  4960. // As with the function-level scope, transfer the inner scopes from the interpreter's side storage
  4961. // to their dedicated register slots.
  4962. SetNonVarReg(this->m_functionBody->FirstInnerScopeReg() + i, InnerScopeFromIndex(i));
  4963. }
  4964. uint newOffset = 0;
  4965. if (fn->GetIsAsmJsFunction())
  4966. {
  4967. AutoRestoreLoopNumbers autoRestore(this, loopNumber, doProfileLoopCheck);
  4968. newOffset = this->CallAsmJsLoopBody((JavascriptMethod)entryPointInfo->address);
  4969. }
  4970. else
  4971. {
  4972. AutoRestoreLoopNumbers autoRestore(this, loopNumber, doProfileLoopCheck);
  4973. newOffset = this->CallLoopBody((JavascriptMethod)entryPointInfo->address);
  4974. }
  4975. if (envReg != Constants::NoRegister)
  4976. {
  4977. SetNonVarReg(envReg, nullptr);
  4978. }
  4979. if (localClosureReg != Constants::NoRegister)
  4980. {
  4981. SetNonVarReg(localClosureReg, nullptr);
  4982. }
  4983. if (localFrameDisplayReg != Constants::NoRegister)
  4984. {
  4985. SetNonVarReg(localFrameDisplayReg, nullptr);
  4986. }
  4987. for (uint32 i = 0; i < innerScopeCount; i++)
  4988. {
  4989. // Get the (possibly updated) scopes from their registers and put them back in side storage.
  4990. // (Getting the updated values may not be necessary, actually, but it can't hurt.)
  4991. // Then null out the registers.
  4992. RegSlot reg = this->m_functionBody->FirstInnerScopeReg() + i;
  4993. SetInnerScopeFromIndex(i, GetNonVarReg(reg));
  4994. SetNonVarReg(reg, nullptr);
  4995. }
  4996. Assert(Js::OpCodeUtil::GetOpCodeLayout(OpCode::ProfiledLoopBodyStart) == Js::OpLayoutType::Unsigned1);
  4997. Assert(Js::OpCodeUtil::GetOpCodeLayout(OpCode::LoopBodyStart) == Js::OpLayoutType::Unsigned1);
  4998. Assert(Js::OpCodeUtil::EncodedSize(Js::OpCode::LoopBodyStart, layoutSize) == Js::OpCodeUtil::EncodedSize(Js::OpCode::ProfiledLoopBodyStart, layoutSize));
  4999. uint byteCodeSize = Js::OpCodeUtil::EncodedSize(Js::OpCode::LoopBodyStart, layoutSize);
  5000. if (layoutSize == SmallLayout)
  5001. {
  5002. byteCodeSize += sizeof(OpLayoutUnsigned1_Small);
  5003. }
  5004. else if (layoutSize == MediumLayout)
  5005. {
  5006. byteCodeSize += sizeof(OpLayoutUnsigned1_Medium);
  5007. }
  5008. else
  5009. {
  5010. byteCodeSize += sizeof(OpLayoutUnsigned1_Large);
  5011. }
  5012. if (newOffset == loopHeader->startOffset || newOffset == m_reader.GetCurrentOffset() - byteCodeSize)
  5013. {
  5014. // If we bail out back the start of the loop, or start of this LoopBodyStart just skip and interpret the loop
  5015. // instead of trying to start the loop body again
  5016. // Increment the interpret count of the loop
  5017. loopHeader->interpretCount++;
  5018. }
  5019. else
  5020. {
  5021. // we do not support this in asmjs, need to add support in IrBuilderAsmjs if we need this support for asmjs
  5022. if (!entryPointInfo->GetIsAsmJSFunction())
  5023. {
  5024. this->CheckIfLoopIsHot(loopHeader->profiledLoopCounter);
  5025. }
  5026. m_reader.SetCurrentOffset(newOffset);
  5027. }
  5028. return loopHeader;
  5029. }
  5030. #endif
  5031. // Increment the interpret count of the loop
  5032. loopHeader->interpretCount += !isFirstIteration;
  5033. const uint loopInterpretCount = GetFunctionBody()->GetLoopInterpretCount(loopHeader);
  5034. if (loopHeader->interpretCount > loopInterpretCount)
  5035. {
  5036. if (this->scriptContext->GetConfig()->IsNoNative())
  5037. {
  5038. return nullptr;
  5039. }
  5040. if (!fn->DoJITLoopBody())
  5041. {
  5042. return nullptr;
  5043. }
  5044. #if ENABLE_NATIVE_CODEGEN
  5045. // If the job is not scheduled then we need to schedule it now.
  5046. // It is possible a job was scheduled earlier and we find ourselves looking at the same entry point
  5047. // again. For example, if the function with the loop was JITed and bailed out then as we finish
  5048. // the call in the interpreter we might encounter a loop for which we had scheduled a JIT job before
  5049. // the function was initially scheduled. In such cases, that old JIT job will complete. If it completes
  5050. // successfully then we can go ahead and use it. If it fails then it will eventually revert to the
  5051. // NotScheduled state. Since transitions from NotScheduled can only occur on the main thread,
  5052. // by checking the state we are safe from racing with the JIT thread when looking at the other fields
  5053. // of the entry point.
  5054. if (entryPointInfo != NULL && entryPointInfo->IsNotScheduled())
  5055. {
  5056. GenerateLoopBody(scriptContext->GetNativeCodeGenerator(), fn, loopHeader, entryPointInfo, fn->GetLocalsCount(), this->m_localSlots);
  5057. }
  5058. #endif
  5059. }
  5060. #if ENABLE_PROFILE_INFO
  5061. else if(
  5062. doProfileLoopCheck &&
  5063. isAutoProfiling &&
  5064. loopHeader->interpretCount > fn->GetLoopProfileThreshold(loopInterpretCount))
  5065. {
  5066. // Start profiling the loop so that the jitted loop body will have some profile data to use
  5067. Assert(!switchProfileMode);
  5068. switchProfileMode = true;
  5069. Assert(switchProfileModeOnLoopEndNumber == 0u - 1);
  5070. switchProfileModeOnLoopEndNumber = loopNumber;
  5071. }
  5072. #endif
  5073. return nullptr;
  5074. }
  5075. void
  5076. InterpreterStackFrame::CheckIfLoopIsHot(uint profiledLoopCounter)
  5077. {
  5078. Js::FunctionBody *fn = this->function->GetFunctionBody();
  5079. if (!fn->GetHasHotLoop() && profiledLoopCounter > (uint)CONFIG_FLAG(JitLoopBodyHotLoopThreshold))
  5080. {
  5081. #ifdef ENABLE_DEBUG_CONFIG_OPTIONS
  5082. if(PHASE_TRACE(Js::JITLoopBodyPhase, fn))
  5083. {
  5084. wchar_t debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE];
  5085. Output::Print(
  5086. L"Speculate Jit set for this function with loopbody: function: %s (%s)\n",
  5087. fn->GetDisplayName(),
  5088. fn->GetDebugNumberSet(debugStringBuffer));
  5089. Output::Flush();
  5090. }
  5091. #endif
  5092. fn->SetHasHotLoop();
  5093. }
  5094. }
  5095. bool InterpreterStackFrame::CheckAndResetImplicitCall(DisableImplicitFlags prevDisableImplicitFlags, ImplicitCallFlags savedImplicitCallFlags)
  5096. {
  5097. ImplicitCallFlags curImplicitCallFlags = this->scriptContext->GetThreadContext()->GetImplicitCallFlags();
  5098. if (curImplicitCallFlags > ImplicitCall_None)
  5099. {
  5100. //error implicit bit is set , reparse without asmjs
  5101. this->scriptContext->GetThreadContext()->SetDisableImplicitFlags(prevDisableImplicitFlags);
  5102. this->scriptContext->GetThreadContext()->SetImplicitCallFlags(savedImplicitCallFlags);
  5103. return true;
  5104. }
  5105. return false;
  5106. }
  5107. uint
  5108. InterpreterStackFrame::CallLoopBody(JavascriptMethod address)
  5109. {
  5110. #ifdef _M_IX86
  5111. void *savedEsp = NULL;
  5112. __asm
  5113. {
  5114. // Save ESP
  5115. mov savedEsp, esp
  5116. // 8-byte align frame to improve floating point perf of our JIT'd code.
  5117. and esp, -8
  5118. // Add an extra 4-bytes to the stack since we'll be pushing 3 arguments
  5119. push eax
  5120. }
  5121. #endif
  5122. #if defined(_M_ARM32_OR_ARM64)
  5123. // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
  5124. // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
  5125. // and do ISB only for 1st time this entry point is called (potential working set regression though).
  5126. _InstructionSynchronizationBarrier();
  5127. #endif
  5128. uint newOffset = ::Math::PointerCastToIntegral<uint>(address(function, CallInfo(CallFlags_InternalFrame, 1), this));
  5129. #ifdef _M_IX86
  5130. _asm
  5131. {
  5132. // Restore ESP
  5133. mov esp, savedEsp
  5134. }
  5135. #endif
  5136. return newOffset;
  5137. }
  5138. uint
  5139. InterpreterStackFrame::CallAsmJsLoopBody(JavascriptMethod address)
  5140. {
  5141. #ifdef _M_IX86
  5142. void *savedEsp = NULL;
  5143. __asm
  5144. {
  5145. // Save ESP
  5146. mov savedEsp, esp
  5147. // Add an extra 4-bytes to the stack since we'll be pushing 3 arguments
  5148. push eax
  5149. }
  5150. #endif
  5151. #if defined(_M_ARM32_OR_ARM64)
  5152. // For ARM we need to make sure that pipeline is synchronized with memory/cache for newly jitted code.
  5153. // Note: this does not seem to affect perf, but if it was, we could add a boolean isCalled to EntryPointInfo
  5154. // and do ISB only for 1st time this entry point is called (potential working set regression though).
  5155. _InstructionSynchronizationBarrier();
  5156. #endif
  5157. uint newOffset = ::Math::PointerCastToIntegral<uint>(address(function, CallInfo(CallFlags_InternalFrame, 1), this));
  5158. #ifdef _M_IX86
  5159. _asm
  5160. {
  5161. // Restore ESP
  5162. mov esp, savedEsp
  5163. }
  5164. #endif
  5165. return newOffset;
  5166. }
  5167. template <class T>
  5168. void InterpreterStackFrame::OP_NewScObjectNoCtorFull(const unaligned T* playout)
  5169. {
  5170. Var function = GetReg(playout->R1);
  5171. Var newObj = JavascriptOperators::NewScObjectNoCtorFull(function, GetScriptContext());
  5172. SetReg(playout->R0, newObj);
  5173. }
  5174. ///----------------------------------------------------------------------------
  5175. ///
  5176. /// InterpreterStackFrame::OP_NewScObject
  5177. ///
  5178. /// OP_NewScObject() allocates a new DynamicObject and initializes it with an
  5179. /// optional "constructor" function.
  5180. ///
  5181. /// NOTE: The return register must be carefully chosen to ensure proper
  5182. /// behavior:
  5183. /// 1. OpCode::NewInstance should never specify "R0" as the register to
  5184. /// store the new instance, because it will get whacked from the
  5185. /// "constructor" function's return value:
  5186. ///
  5187. /// var a1 = Date(); <-- a1 = string returned from Date() function
  5188. /// var a2 = new Date(); <-- a2 = instance return from NewInstance.
  5189. /// Date()'s return value is thrown away.
  5190. ///
  5191. /// 2. If an exception is thrown during construction, the destination
  5192. /// variable / field should __not__ be modified. Therefore, the destination
  5193. /// register should always be a temporary and never a valid local variable.
  5194. /// After successfully returning from the constructor function, the new
  5195. /// instance is valid and may be stored in its final destination variable /
  5196. /// field.
  5197. ///
  5198. /// OPCODE NewObject:
  5199. /// T1 = new DynamicObject(Function.Prototype)
  5200. /// OutArg[0] = T1
  5201. /// Call(Function, ArgCount)
  5202. /// Local[Return] = T1
  5203. ///
  5204. /// - R0: Destination "local" register
  5205. /// - R1: Optional constructor JavascriptFunction instance or 'null'
  5206. ///
  5207. ///----------------------------------------------------------------------------
  5208. template <class T, bool Profiled, bool ICIndex>
  5209. void InterpreterStackFrame::OP_NewScObject_Impl(const unaligned T* playout, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
  5210. {
  5211. if (ICIndex)
  5212. {
  5213. Assert(inlineCacheIndex != Js::Constants::NoInlineCacheIndex);
  5214. }
  5215. Var newVarInstance =
  5216. #if ENABLE_PROFILE_INFO
  5217. Profiled ?
  5218. ProfiledNewScObject_Helper(
  5219. GetReg(playout->Function),
  5220. playout->ArgCount,
  5221. static_cast<const unaligned OpLayoutDynamicProfile<T> *>(playout)->profileId,
  5222. inlineCacheIndex,
  5223. spreadIndices) :
  5224. #endif
  5225. NewScObject_Helper(GetReg(playout->Function), playout->ArgCount, spreadIndices);
  5226. SetReg((RegSlot)playout->Return, newVarInstance);
  5227. }
  5228. template <class T, bool Profiled>
  5229. void InterpreterStackFrame::OP_NewScObjArray_Impl(const unaligned T* playout, const Js::AuxArray<uint32> *spreadIndices)
  5230. {
  5231. // Always profile this operation when auto-profiling so that array type changes are tracked
  5232. #if ENABLE_PROFILE_INFO
  5233. if (!Profiled && !isAutoProfiling)
  5234. #else
  5235. Assert(!Profiled);
  5236. #endif
  5237. {
  5238. OP_NewScObject_Impl<T, Profiled, false>(playout, Js::Constants::NoInlineCacheIndex, spreadIndices);
  5239. return;
  5240. }
  5241. #if ENABLE_PROFILE_INFO
  5242. Arguments args(CallInfo(CallFlags_New, playout->ArgCount), m_outParams);
  5243. uint32 spreadSize = 0;
  5244. if (spreadIndices != nullptr)
  5245. {
  5246. spreadSize = JavascriptFunction::GetSpreadSize(args, spreadIndices, scriptContext);
  5247. // Allocate room on the stack for the spread args.
  5248. Arguments outArgs(CallInfo(CallFlags_New, 0), nullptr);
  5249. outArgs.Info.Count = spreadSize;
  5250. const unsigned STACK_ARGS_ALLOCA_THRESHOLD = 8; // Number of stack args we allow before using _alloca
  5251. Var stackArgs[STACK_ARGS_ALLOCA_THRESHOLD];
  5252. size_t outArgsSize = 0;
  5253. if (outArgs.Info.Count > STACK_ARGS_ALLOCA_THRESHOLD)
  5254. {
  5255. PROBE_STACK(scriptContext, outArgs.Info.Count * sizeof(Var) + Js::Constants::MinStackDefault); // args + function call
  5256. outArgsSize = outArgs.Info.Count * sizeof(Var);
  5257. outArgs.Values = (Var*)_alloca(outArgsSize);
  5258. }
  5259. else
  5260. {
  5261. outArgs.Values = stackArgs;
  5262. outArgsSize = STACK_ARGS_ALLOCA_THRESHOLD * sizeof(Var);
  5263. ZeroMemory(outArgs.Values, outArgsSize); // We may not use all of the elements
  5264. }
  5265. JavascriptFunction::SpreadArgs(args, outArgs, spreadIndices, scriptContext);
  5266. SetReg(
  5267. (RegSlot)playout->Return,
  5268. ProfilingHelpers::ProfiledNewScObjArray(
  5269. GetReg(playout->Function),
  5270. outArgs,
  5271. function,
  5272. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId,
  5273. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId2));
  5274. }
  5275. else
  5276. {
  5277. SetReg(
  5278. (RegSlot)playout->Return,
  5279. ProfilingHelpers::ProfiledNewScObjArray(
  5280. GetReg(playout->Function),
  5281. args,
  5282. function,
  5283. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId,
  5284. static_cast<const unaligned OpLayoutDynamicProfile2<T> *>(playout)->profileId2));
  5285. }
  5286. PopOut(playout->ArgCount);
  5287. #endif
  5288. }
  5289. void InterpreterStackFrame::OP_NewScObject_A_Impl(const unaligned OpLayoutAuxiliary * playout, RegSlot *target)
  5290. {
  5291. const Js::VarArrayVarCount * vars = Js::ByteCodeReader::ReadVarArrayVarCount(playout->Offset, this->GetFunctionBody());
  5292. int count = Js::TaggedInt::ToInt32(vars->count);
  5293. // Push the parameters to stack
  5294. for (int i=0;i<count; i++)
  5295. {
  5296. SetOut( (ArgSlot)(i+1), vars->elements[i]);
  5297. }
  5298. Var newVarInstance = NewScObject_Helper(GetReg((RegSlot)playout->C1), (ArgSlot)count+1);
  5299. SetReg((RegSlot)playout->R0, newVarInstance);
  5300. }
  5301. Var InterpreterStackFrame::NewScObject_Helper(Var target, ArgSlot ArgCount, const Js::AuxArray<uint32> *spreadIndices)
  5302. {
  5303. Arguments args(CallInfo(CallFlags_New, ArgCount), m_outParams);
  5304. Var newVarInstance = JavascriptOperators::NewScObject(target, args, GetScriptContext(), spreadIndices);
  5305. PopOut(ArgCount);
  5306. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newVarInstance));
  5307. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5308. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5309. {
  5310. newVarInstance = JavascriptProxy::AutoProxyWrapper(newVarInstance);
  5311. // this might come from a different scriptcontext.
  5312. newVarInstance = CrossSite::MarshalVar(GetScriptContext(), newVarInstance);
  5313. }
  5314. #endif
  5315. #ifdef ENABLE_BASIC_TELEMETRY
  5316. {
  5317. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().NewScriptObject( target, args, newVarInstance );
  5318. }
  5319. #endif
  5320. return newVarInstance;
  5321. }
  5322. #if ENABLE_PROFILE_INFO
  5323. Var InterpreterStackFrame::ProfiledNewScObject_Helper(Var target, ArgSlot ArgCount, ProfileId profileId, InlineCacheIndex inlineCacheIndex, const Js::AuxArray<uint32> *spreadIndices)
  5324. {
  5325. Arguments args(CallInfo(CallFlags_New, ArgCount), m_outParams);
  5326. Var newVarInstance =
  5327. ProfilingHelpers::ProfiledNewScObject(
  5328. target,
  5329. args,
  5330. GetFunctionBody(),
  5331. profileId,
  5332. inlineCacheIndex,
  5333. spreadIndices);
  5334. PopOut(ArgCount);
  5335. JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(newVarInstance));
  5336. #if ENABLE_DEBUG_CONFIG_OPTIONS
  5337. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  5338. {
  5339. newVarInstance = JavascriptProxy::AutoProxyWrapper(newVarInstance);
  5340. // this might come from a different scriptcontext.
  5341. newVarInstance = CrossSite::MarshalVar(GetScriptContext(), newVarInstance);
  5342. }
  5343. #endif
  5344. #ifdef TELEMETRY_PROFILED
  5345. {
  5346. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().NewScriptObject( target, args, newVarInstance );
  5347. }
  5348. #endif
  5349. return newVarInstance;
  5350. }
  5351. #endif
  5352. template <typename T>
  5353. void InterpreterStackFrame::OP_LdElementUndefined(const unaligned OpLayoutT_ElementU<T>* playout)
  5354. {
  5355. if (this->m_functionBody->IsEval())
  5356. {
  5357. JavascriptOperators::OP_LoadUndefinedToElementDynamic(GetReg(playout->Instance),
  5358. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  5359. }
  5360. else
  5361. {
  5362. JavascriptOperators::OP_LoadUndefinedToElement(GetReg(playout->Instance),
  5363. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
  5364. }
  5365. }
  5366. template <typename T>
  5367. void InterpreterStackFrame::OP_LdLocalElementUndefined(const unaligned OpLayoutT_ElementRootU<T>* playout)
  5368. {
  5369. if (this->m_functionBody->IsEval())
  5370. {
  5371. JavascriptOperators::OP_LoadUndefinedToElementDynamic(this->localClosure,
  5372. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  5373. }
  5374. else
  5375. {
  5376. JavascriptOperators::OP_LoadUndefinedToElement(this->localClosure,
  5377. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
  5378. }
  5379. }
  5380. template <typename T>
  5381. void InterpreterStackFrame::OP_LdElementUndefinedScoped(const unaligned OpLayoutT_ElementScopedU<T>* playout)
  5382. {
  5383. // Implicit root object as default instance
  5384. JavascriptOperators::OP_LoadUndefinedToElementScoped(GetEnvForEvalCode(),
  5385. this->m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
  5386. }
  5387. void InterpreterStackFrame::OP_ChkUndecl(Var aValue)
  5388. {
  5389. if (this->scriptContext->IsUndeclBlockVar(aValue))
  5390. {
  5391. JavascriptError::ThrowReferenceError(scriptContext, JSERR_UseBeforeDeclaration);
  5392. }
  5393. }
  5394. void InterpreterStackFrame::OP_ChkNewCallFlag()
  5395. {
  5396. if (!(this->m_callFlags & CallFlags_New))
  5397. {
  5398. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew);
  5399. }
  5400. }
  5401. void InterpreterStackFrame::OP_EnsureNoRootProperty(uint propertyIdIndex)
  5402. {
  5403. Var instance = this->GetRootObject();
  5404. JavascriptOperators::OP_EnsureNoRootProperty(instance, this->m_functionBody->GetReferencedPropertyId(propertyIdIndex));
  5405. }
  5406. void InterpreterStackFrame::OP_EnsureNoRootRedeclProperty(uint propertyIdIndex)
  5407. {
  5408. Var instance = this->GetRootObject();
  5409. JavascriptOperators::OP_EnsureNoRootRedeclProperty(instance, this->m_functionBody->GetReferencedPropertyId(propertyIdIndex));
  5410. }
  5411. void InterpreterStackFrame::OP_ScopedEnsureNoRedeclProperty(Var aValue, uint propertyIdIndex, Var aValue2)
  5412. {
  5413. Js::PropertyId propertyId = this->m_functionBody->GetReferencedPropertyId(propertyIdIndex);
  5414. JavascriptOperators::OP_ScopedEnsureNoRedeclProperty((FrameDisplay*)aValue, propertyId, aValue2);
  5415. }
  5416. Var InterpreterStackFrame::OP_InitUndecl()
  5417. {
  5418. return this->scriptContext->GetLibrary()->GetUndeclBlockVar();
  5419. }
  5420. void InterpreterStackFrame::OP_InitUndeclSlot(Var aValue, int32 slot)
  5421. {
  5422. this->OP_StSlot(aValue, slot, this->scriptContext->GetLibrary()->GetUndeclBlockVar());
  5423. }
  5424. void InterpreterStackFrame::OP_TryCatch(const unaligned OpLayoutBr* playout)
  5425. {
  5426. Js::JavascriptExceptionObject* exception = NULL;
  5427. try
  5428. {
  5429. this->nestedTryDepth++;
  5430. // mark the stackFrame as 'in try block'
  5431. this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
  5432. Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
  5433. if (scriptContext->IsInDebugMode())
  5434. {
  5435. this->ProcessWithDebugging();
  5436. this->TrySetRetOffset();
  5437. }
  5438. else
  5439. {
  5440. this->Process();
  5441. this->TrySetRetOffset();
  5442. }
  5443. }
  5444. catch (Js::JavascriptExceptionObject * exceptionObject)
  5445. {
  5446. // We are using C++ exception handling which does not unwind the stack in the catch block.
  5447. // For stack overflow and OOM exceptions, we cannot run user code here because the stack is not unwind.
  5448. exception = exceptionObject;
  5449. }
  5450. if (--this->nestedTryDepth == -1)
  5451. {
  5452. // unmark the stackFrame as 'in try block'
  5453. this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
  5454. }
  5455. // Now that the stack is unwound, let's run the catch block.
  5456. if (exception)
  5457. {
  5458. if (exception->IsGeneratorReturnException())
  5459. {
  5460. // Generator return scenario, so no need to go into the catch block and we must rethrow to propagate the exception to down level
  5461. throw exception;
  5462. }
  5463. exception = exception->CloneIfStaticExceptionObject(scriptContext);
  5464. // We've got a JS exception. Grab the exception object and assign it to the
  5465. // catch object's location, then call the handler (i.e., we consume the Catch op here).
  5466. Var catchObject = exception->GetThrownObject(scriptContext);
  5467. m_reader.SetCurrentRelativeOffset((const byte *)(playout + 1), playout->RelativeJumpOffset);
  5468. LayoutSize layoutSize;
  5469. OpCode catchOp = m_reader.ReadOp(layoutSize);
  5470. #ifdef BYTECODE_BRANCH_ISLAND
  5471. if (catchOp == Js::OpCode::BrLong)
  5472. {
  5473. Assert(layoutSize == SmallLayout);
  5474. auto playoutBrLong = m_reader.BrLong();
  5475. m_reader.SetCurrentRelativeOffset((const byte *)(playoutBrLong + 1), playoutBrLong->RelativeJumpOffset);
  5476. catchOp = m_reader.ReadOp(layoutSize);
  5477. }
  5478. #endif
  5479. AssertMsg(catchOp == OpCode::Catch, "Catch op not found at catch offset");
  5480. RegSlot reg = layoutSize == SmallLayout ? m_reader.Reg1_Small()->R0 :
  5481. layoutSize == MediumLayout ? m_reader.Reg1_Medium()->R0 : m_reader.Reg1_Large()->R0;
  5482. SetReg(reg, catchObject);
  5483. ResetOut();
  5484. this->nestedCatchDepth++;
  5485. // mark the stackFrame as 'in catch block'
  5486. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5487. this->ProcessCatch();
  5488. if (--this->nestedCatchDepth == -1)
  5489. {
  5490. // unmark the stackFrame as 'in catch block'
  5491. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5492. }
  5493. }
  5494. }
  5495. void InterpreterStackFrame::ProcessCatch()
  5496. {
  5497. if (this->scriptContext->IsInDebugMode())
  5498. {
  5499. this->DebugProcess();
  5500. }
  5501. else
  5502. {
  5503. this->Process();
  5504. }
  5505. }
  5506. int InterpreterStackFrame::ProcessFinally()
  5507. {
  5508. this->nestedFinallyDepth++;
  5509. // mark the stackFrame as 'in finally block'
  5510. this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
  5511. int newOffset = 0;
  5512. if (scriptContext->IsInDebugMode())
  5513. {
  5514. newOffset = ::Math::PointerCastToIntegral<int>(this->DebugProcess());
  5515. }
  5516. else
  5517. {
  5518. newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
  5519. }
  5520. if (--this->nestedFinallyDepth == -1)
  5521. {
  5522. // unmark the stackFrame as 'in finally block'
  5523. this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
  5524. }
  5525. return newOffset;
  5526. }
  5527. void InterpreterStackFrame::ProcessTryCatchBailout(EHBailoutData * ehBailoutData, uint32 tryNestingDepth)
  5528. {
  5529. int catchOffset = ehBailoutData->catchOffset;
  5530. Js::JavascriptExceptionObject* exception = NULL;
  5531. if (catchOffset != 0)
  5532. {
  5533. try
  5534. {
  5535. this->nestedTryDepth++;
  5536. // mark the stackFrame as 'in try block'
  5537. this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
  5538. if (tryNestingDepth != 0)
  5539. {
  5540. this->ProcessTryCatchBailout(ehBailoutData->child, --tryNestingDepth);
  5541. }
  5542. Js::JavascriptExceptionOperators::AutoCatchHandlerExists autoCatchHandlerExists(scriptContext);
  5543. if (scriptContext->IsInDebugMode())
  5544. {
  5545. this->ProcessWithDebugging();
  5546. this->TrySetRetOffset();
  5547. }
  5548. else
  5549. {
  5550. this->Process();
  5551. this->TrySetRetOffset();
  5552. }
  5553. }
  5554. catch (Js::JavascriptExceptionObject * exceptionObject)
  5555. {
  5556. // We are using C++ exception handling which does not unwind the stack in the catch block.
  5557. // For stack overflow and OOM exceptions, we cannot run user code here because the stack is not unwind.
  5558. exception = exceptionObject;
  5559. }
  5560. }
  5561. else
  5562. {
  5563. this->nestedCatchDepth++;
  5564. // mark the stackFrame as 'in catch block'
  5565. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5566. if (tryNestingDepth != 0)
  5567. {
  5568. this->ProcessTryCatchBailout(ehBailoutData->child, --tryNestingDepth);
  5569. }
  5570. this->ProcessCatch();
  5571. if (--this->nestedCatchDepth == -1)
  5572. {
  5573. // unmark the stackFrame as 'in catch block'
  5574. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5575. }
  5576. return;
  5577. }
  5578. if (--this->nestedTryDepth == -1)
  5579. {
  5580. // unmark the stackFrame as 'in try block'
  5581. this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
  5582. }
  5583. // Now that the stack is unwound, let's run the catch block.
  5584. if (exception)
  5585. {
  5586. if (exception->IsGeneratorReturnException())
  5587. {
  5588. // Generator return scenario, so no need to go into the catch block and we must rethrow to propagate the exception to down level
  5589. throw exception;
  5590. }
  5591. exception = exception->CloneIfStaticExceptionObject(scriptContext);
  5592. // We've got a JS exception. Grab the exception object and assign it to the
  5593. // catch object's location, then call the handler (i.e., we consume the Catch op here).
  5594. Var catchObject = exception->GetThrownObject(scriptContext);
  5595. m_reader.SetCurrentOffset(catchOffset);
  5596. LayoutSize layoutSize;
  5597. OpCode catchOp = m_reader.ReadOp(layoutSize);
  5598. #ifdef BYTECODE_BRANCH_ISLAND
  5599. if (catchOp == Js::OpCode::BrLong)
  5600. {
  5601. Assert(layoutSize == SmallLayout);
  5602. auto playoutBrLong = m_reader.BrLong();
  5603. m_reader.SetCurrentRelativeOffset((const byte *)(playoutBrLong + 1), playoutBrLong->RelativeJumpOffset);
  5604. catchOp = m_reader.ReadOp(layoutSize);
  5605. }
  5606. #endif
  5607. AssertMsg(catchOp == OpCode::Catch, "Catch op not found at catch offset");
  5608. RegSlot reg = layoutSize == SmallLayout ? m_reader.Reg1_Small()->R0 :
  5609. layoutSize == MediumLayout ? m_reader.Reg1_Medium()->R0 : m_reader.Reg1_Large()->R0;
  5610. SetReg(reg, catchObject);
  5611. ResetOut();
  5612. this->nestedCatchDepth++;
  5613. // mark the stackFrame as 'in catch block'
  5614. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5615. this->ProcessCatch();
  5616. if (--this->nestedCatchDepth == -1)
  5617. {
  5618. // unmark the stackFrame as 'in catch block'
  5619. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5620. }
  5621. }
  5622. return;
  5623. }
  5624. void InterpreterStackFrame::TrySetRetOffset()
  5625. {
  5626. Assert(this->m_flags & Js::InterpreterStackFrameFlags_WithinTryBlock);
  5627. // It may happen that a JITted loop body returned the offset of RET. If the loop body was
  5628. // called from a try, the interpreter "Process()" should also just return.
  5629. if (this->retOffset != 0)
  5630. {
  5631. m_reader.SetCurrentOffset(this->retOffset);
  5632. }
  5633. }
  5634. bool InterpreterStackFrame::IsInCatchOrFinallyBlock()
  5635. {
  5636. return (this->m_flags & Js::InterpreterStackFrameFlags_WithinCatchBlock) ||
  5637. (this->m_flags & Js::InterpreterStackFrameFlags_WithinFinallyBlock);
  5638. }
  5639. void InterpreterStackFrame::OP_ResumeCatch()
  5640. {
  5641. this->m_flags |= InterpreterStackFrameFlags_WithinCatchBlock;
  5642. if (scriptContext->IsInDebugMode())
  5643. {
  5644. this->DebugProcess();
  5645. }
  5646. else
  5647. {
  5648. this->Process();
  5649. }
  5650. this->m_flags &= ~InterpreterStackFrameFlags_WithinCatchBlock;
  5651. }
  5652. /// ---------------------------------------------------------------------------------------------------
  5653. /// The behavior we want is the following:
  5654. /// - If the control leaves the user's try without throwing, execute the finally and continue
  5655. /// after the end of the try.
  5656. /// - If the user code throws, catch this exception and then execute this finally while unwinding to
  5657. /// the handler (if any).
  5658. /// ---------------------------------------------------------------------------------------------------
  5659. void InterpreterStackFrame::ProcessTryFinally(const byte* ip, Js::JumpOffset jumpOffset, Js::RegSlot regException, Js::RegSlot regOffset, bool hasYield)
  5660. {
  5661. Js::JavascriptExceptionObject* pExceptionObject = nullptr;
  5662. bool skipFinallyBlock = false;
  5663. try
  5664. {
  5665. Js::Var result = nullptr;
  5666. this->nestedTryDepth++;
  5667. // mark the stackFrame as 'in try block'
  5668. this->m_flags |= InterpreterStackFrameFlags_WithinTryBlock;
  5669. if (scriptContext->IsInDebugMode())
  5670. {
  5671. result = this->ProcessWithDebugging();
  5672. }
  5673. else
  5674. {
  5675. result = this->Process();
  5676. }
  5677. if (result == nullptr)
  5678. {
  5679. Assert(hasYield);
  5680. skipFinallyBlock = true;
  5681. }
  5682. }
  5683. catch (Js::JavascriptExceptionObject * e)
  5684. {
  5685. pExceptionObject = e;
  5686. }
  5687. if (--this->nestedTryDepth == -1)
  5688. {
  5689. // unmark the stackFrame as 'in try block'
  5690. this->m_flags &= ~InterpreterStackFrameFlags_WithinTryBlock;
  5691. }
  5692. if (skipFinallyBlock)
  5693. {
  5694. // A leave occurred due to a yield
  5695. return;
  5696. }
  5697. // Save the current IP so execution can continue there if the finally doesn't
  5698. // take control of the flow.
  5699. int newOffset = 0;
  5700. int currOffset = m_reader.GetCurrentOffset();
  5701. if (hasYield)
  5702. {
  5703. // save the exception if there is one to a register in case we yield during the finally block
  5704. // and need to get that exception object back upon resume in OP_ResumeFinally
  5705. SetNonVarReg(regException, pExceptionObject);
  5706. SetNonVarReg(regOffset, reinterpret_cast<Js::Var>(currOffset));
  5707. }
  5708. if (pExceptionObject && !pExceptionObject->IsGeneratorReturnException())
  5709. {
  5710. // Clone static exception object early in case finally block overwrites it
  5711. pExceptionObject = pExceptionObject->CloneIfStaticExceptionObject(scriptContext);
  5712. }
  5713. if (pExceptionObject && scriptContext->IsInDebugMode() &&
  5714. pExceptionObject != scriptContext->GetThreadContext()->GetPendingSOErrorObject())
  5715. {
  5716. // Swallowing an exception that has triggered a finally is not implemented
  5717. // (This appears to be the same behavior as ie8)
  5718. pExceptionObject->SetDebuggerSkip(false);
  5719. }
  5720. // Call into the finally by setting the IP, consuming the Finally, and letting the interpreter recurse.
  5721. m_reader.SetCurrentRelativeOffset(ip, jumpOffset);
  5722. ResetOut();
  5723. newOffset = this->ProcessFinally();
  5724. bool endOfFinallyBlock = newOffset == 0;
  5725. if (endOfFinallyBlock)
  5726. {
  5727. // Finally completed without taking over the flow. Resume where we left off before calling it.
  5728. m_reader.SetCurrentOffset(currOffset);
  5729. }
  5730. else
  5731. {
  5732. // Finally seized the flow with a jump out of its scope. Resume at the jump target and
  5733. // force the runtime to return to this frame without executing the catch.
  5734. m_reader.SetCurrentOffset(newOffset);
  5735. return;
  5736. }
  5737. if (pExceptionObject && (endOfFinallyBlock || !pExceptionObject->IsGeneratorReturnException()))
  5738. {
  5739. throw pExceptionObject;
  5740. }
  5741. }
  5742. void InterpreterStackFrame::OP_TryFinally(const unaligned OpLayoutBr* playout)
  5743. {
  5744. ProcessTryFinally((const byte*)(playout + 1), playout->RelativeJumpOffset);
  5745. }
  5746. void InterpreterStackFrame::OP_TryFinallyWithYield(const byte* ip, Js::JumpOffset jumpOffset, Js::RegSlot regException, Js::RegSlot regOffset)
  5747. {
  5748. ProcessTryFinally(ip, jumpOffset, regException, regOffset, true);
  5749. }
  5750. void InterpreterStackFrame::OP_ResumeFinally(const byte* ip, Js::JumpOffset jumpOffset, RegSlot exceptionRegSlot, RegSlot offsetRegSlot)
  5751. {
  5752. this->m_flags |= InterpreterStackFrameFlags_WithinFinallyBlock;
  5753. int newOffset = 0;
  5754. if (scriptContext->IsInDebugMode())
  5755. {
  5756. newOffset = ::Math::PointerCastToIntegral<int>(this->DebugProcess());
  5757. }
  5758. else
  5759. {
  5760. newOffset = ::Math::PointerCastToIntegral<int>(this->Process());
  5761. }
  5762. this->m_flags &= ~InterpreterStackFrameFlags_WithinFinallyBlock;
  5763. bool endOfFinallyBlock = newOffset == 0;
  5764. if (endOfFinallyBlock)
  5765. {
  5766. // Finally completed without taking over the flow. Resume where we left off before calling it.
  5767. int currOffset = ::Math::PointerCastToIntegral<int>(GetNonVarReg(offsetRegSlot));
  5768. m_reader.SetCurrentOffset(currOffset);
  5769. }
  5770. else
  5771. {
  5772. // Finally seized the flow with a jump out of its scope. Resume at the jump target and
  5773. // force the runtime to return to this frame without executing the catch.
  5774. m_reader.SetCurrentOffset(newOffset);
  5775. return;
  5776. }
  5777. Js::JavascriptExceptionObject* exceptionObj = (Js::JavascriptExceptionObject*)GetNonVarReg(exceptionRegSlot);
  5778. if (exceptionObj && (endOfFinallyBlock || !exceptionObj->IsGeneratorReturnException()))
  5779. {
  5780. throw exceptionObj;
  5781. }
  5782. }
  5783. template <typename T>
  5784. void InterpreterStackFrame::OP_IsInst(const unaligned T* playout)
  5785. {
  5786. Var instance = GetReg(playout->R1);
  5787. Var function = GetReg(playout->R2);
  5788. IsInstInlineCache *inlineCache = this->GetIsInstInlineCache(playout->inlineCacheIndex);
  5789. ScriptContext* scriptContext = GetScriptContext();
  5790. Var result = JavascriptOperators::OP_IsInst(instance, function, scriptContext, inlineCache);
  5791. #ifdef ENABLE_BASIC_TELEMETRY
  5792. {
  5793. this->scriptContext->GetTelemetry().GetOpcodeTelemetry().IsInstanceOf(instance, function, result);
  5794. }
  5795. #endif
  5796. SetReg(playout->R0, result);
  5797. }
  5798. template <typename T>
  5799. void InterpreterStackFrame::OP_ApplyArgs(const unaligned OpLayoutT_Reg5<T> * playout)
  5800. {
  5801. // Always save and restore implicit call flags when calling out
  5802. // REVIEW: Can we avoid it if we don't collect dynamic profile info?
  5803. ThreadContext * threadContext = scriptContext->GetThreadContext();
  5804. Js::ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  5805. // Currently ApplyArgs is equivalent to CallFldVoid (where we don't use the return value)
  5806. Var v=GetNonVarReg(playout->R4);
  5807. JavascriptOperators::OP_ApplyArgs(GetReg(playout->R1),GetReg(playout->R2),
  5808. (void**)GetNonVarReg(playout->R3),*((CallInfo*)&v),GetScriptContext());
  5809. threadContext->SetImplicitCallFlags(savedImplicitCallFlags);
  5810. }
  5811. void InterpreterStackFrame::OP_SpreadArrayLiteral(const unaligned OpLayoutReg2Aux * playout)
  5812. {
  5813. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  5814. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  5815. threadContext->ClearImplicitCallFlags();
  5816. Var instance = GetReg(playout->R1);
  5817. #if ENABLE_COPYONACCESS_ARRAY
  5818. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Var>(instance);
  5819. #endif
  5820. const Js::AuxArray<uint32> *spreadIndices = m_reader.ReadAuxArray<uint32>(playout->Offset, this->GetFunctionBody());
  5821. ScriptContext* scriptContext = GetScriptContext();
  5822. Var result = JavascriptArray::SpreadArrayArgs(instance, spreadIndices, scriptContext);
  5823. threadContext->CheckAndResetImplicitCallAccessorFlag();
  5824. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  5825. SetReg(playout->R0, result);
  5826. }
  5827. FrameDisplay *
  5828. InterpreterStackFrame::OP_LdInnerFrameDisplay(void *argHead, void *argEnv, ScriptContext *scriptContext)
  5829. {
  5830. JavascriptOperators::CheckInnerFrameDisplayArgument(argHead);
  5831. return OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  5832. }
  5833. FrameDisplay *
  5834. InterpreterStackFrame::OP_LdInnerFrameDisplayNoParent(void *argHead, ScriptContext *scriptContext)
  5835. {
  5836. JavascriptOperators::CheckInnerFrameDisplayArgument(argHead);
  5837. return OP_LdFrameDisplayNoParent<true>(argHead, scriptContext);
  5838. }
  5839. FrameDisplay *
  5840. InterpreterStackFrame::OP_LdFrameDisplay(void *argHead, void *argEnv, ScriptContext *scriptContext)
  5841. {
  5842. FrameDisplay *frameDisplay;
  5843. bool strict = this->m_functionBody->GetIsStrictMode();
  5844. if (strict)
  5845. {
  5846. frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
  5847. }
  5848. else
  5849. {
  5850. frameDisplay = JavascriptOperators::OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  5851. }
  5852. return frameDisplay;
  5853. }
  5854. FrameDisplay *
  5855. InterpreterStackFrame::OP_LdFrameDisplaySetLocal(void *argHead, void *argEnv, ScriptContext *scriptContext)
  5856. {
  5857. FrameDisplay *frameDisplay = OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  5858. this->SetLocalFrameDisplay(frameDisplay);
  5859. return frameDisplay;
  5860. }
  5861. FrameDisplay *
  5862. InterpreterStackFrame::NewFrameDisplay(void *argHead, void *argEnv)
  5863. {
  5864. FrameDisplay *frameDisplay;
  5865. bool strict = this->m_functionBody->GetIsStrictMode();
  5866. if (!this->m_functionBody->DoStackFrameDisplay() || !this->GetLocalFrameDisplay())
  5867. {
  5868. // Null local frame display probably indicates that we bailed out of an inlinee.
  5869. // Once we support stack closures in inlined functions, we can just assert that this value
  5870. // is never null if we should be allocating on the stack.
  5871. return this->OP_LdFrameDisplaySetLocal(argHead, argEnv, this->GetScriptContext());
  5872. }
  5873. frameDisplay = this->GetLocalFrameDisplay();
  5874. Assert(frameDisplay != nullptr);
  5875. frameDisplay->SetTag(true);
  5876. frameDisplay->SetStrictMode(strict);
  5877. frameDisplay->SetLength(this->m_functionBody->GetEnvDepth() + 1);
  5878. Assert(frameDisplay->GetLength() == ((FrameDisplay*)argEnv)->GetLength() + 1);
  5879. for (uint i = 0; i < ((FrameDisplay*)argEnv)->GetLength(); i++)
  5880. {
  5881. frameDisplay->SetItem(i + 1, ((FrameDisplay*)argEnv)->GetItem(i));
  5882. }
  5883. frameDisplay->SetItem(0, argHead);
  5884. return frameDisplay;
  5885. }
  5886. template<bool innerFD>
  5887. FrameDisplay *
  5888. InterpreterStackFrame::OP_LdFrameDisplayNoParent(void *argHead, ScriptContext *scriptContext)
  5889. {
  5890. FrameDisplay *frameDisplay;
  5891. bool strict = this->m_functionBody->GetIsStrictMode();
  5892. Var argEnv = nullptr;
  5893. if (innerFD && this->m_functionBody->GetLocalFrameDisplayReg() != Constants::NoRegister)
  5894. {
  5895. argEnv = this->GetLocalFrameDisplay();
  5896. }
  5897. if (argEnv == nullptr && this->m_functionBody->GetEnvReg() != Constants::NoRegister)
  5898. {
  5899. argEnv = this->LdEnv();
  5900. }
  5901. if (argEnv == nullptr)
  5902. {
  5903. if (strict)
  5904. {
  5905. frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplayNoParent(argHead, scriptContext);
  5906. }
  5907. else
  5908. {
  5909. frameDisplay = JavascriptOperators::OP_LdFrameDisplayNoParent(argHead, scriptContext);
  5910. }
  5911. }
  5912. else
  5913. {
  5914. if (strict)
  5915. {
  5916. frameDisplay = JavascriptOperators::OP_LdStrictFrameDisplay(argHead, argEnv, scriptContext);
  5917. }
  5918. else
  5919. {
  5920. frameDisplay = JavascriptOperators::OP_LdFrameDisplay(argHead, argEnv, scriptContext);
  5921. }
  5922. }
  5923. return frameDisplay;
  5924. }
  5925. FrameDisplay *
  5926. InterpreterStackFrame::OP_LdFuncExprFrameDisplaySetLocal(void *argHead1, void *argHead2, ScriptContext *scriptContext)
  5927. {
  5928. FrameDisplay *frameDisplay = OP_LdFrameDisplayNoParent<false>(argHead2, scriptContext);
  5929. frameDisplay = OP_LdFrameDisplay(argHead1, frameDisplay, scriptContext);
  5930. this->SetLocalFrameDisplay(frameDisplay);
  5931. return frameDisplay;
  5932. }
  5933. FrameDisplay* InterpreterStackFrame::GetLocalFrameDisplay() const
  5934. {
  5935. return this->localFrameDisplay;
  5936. }
  5937. void InterpreterStackFrame::SetLocalFrameDisplay(FrameDisplay* frameDisplay)
  5938. {
  5939. this->localFrameDisplay = frameDisplay;
  5940. }
  5941. Var InterpreterStackFrame::GetLocalClosure() const
  5942. {
  5943. return this->localClosure;
  5944. }
  5945. void InterpreterStackFrame::SetLocalClosure(Var closure)
  5946. {
  5947. this->localClosure = closure;
  5948. }
  5949. void
  5950. InterpreterStackFrame::OP_NewInnerScopeSlots(uint innerScopeIndex, uint count, int scopeIndex, ScriptContext *scriptContext, FunctionBody *functionBody)
  5951. {
  5952. Var * slotArray;
  5953. slotArray =
  5954. JavascriptOperators::OP_NewScopeSlotsWithoutPropIds(count, scopeIndex, scriptContext, functionBody);
  5955. this->SetInnerScopeFromIndex(innerScopeIndex, slotArray);
  5956. }
  5957. template <typename T>
  5958. void InterpreterStackFrame::OP_CloneInnerScopeSlots(const unaligned OpLayoutT_Unsigned1<T> *playout)
  5959. {
  5960. uint innerScopeIndex = playout->C1;
  5961. Var * slotArray;
  5962. slotArray = (Var*)this->InnerScopeFromIndex(innerScopeIndex);
  5963. slotArray = JavascriptOperators::OP_CloneScopeSlots(slotArray, scriptContext);
  5964. this->SetInnerScopeFromIndex(innerScopeIndex, slotArray);
  5965. }
  5966. template <typename T>
  5967. void InterpreterStackFrame::OP_CloneBlockScope(const unaligned OpLayoutT_Unsigned1<T> *playout)
  5968. {
  5969. uint innerScopeIndex = playout->C1;
  5970. Var scope = this->InnerScopeFromIndex(innerScopeIndex);
  5971. BlockActivationObject* blockScope = BlockActivationObject::FromVar(scope);
  5972. scope = JavascriptOperators::OP_CloneBlockScope(blockScope, scriptContext);
  5973. this->SetInnerScopeFromIndex(innerScopeIndex, scope);
  5974. }
  5975. Var *
  5976. InterpreterStackFrame::NewScopeSlots(unsigned int size, ScriptContext *scriptContext, Var scope)
  5977. {
  5978. Var * slotArray;
  5979. slotArray = JavascriptOperators::OP_NewScopeSlots(size, scriptContext, scope);
  5980. this->SetLocalClosure(slotArray);
  5981. return slotArray;
  5982. }
  5983. Var *
  5984. InterpreterStackFrame::NewScopeSlots()
  5985. {
  5986. Var * slotArray;
  5987. FunctionBody * functionBody = this->m_functionBody;
  5988. uint scopeSlotCount = functionBody->scopeSlotArraySize;
  5989. Assert(scopeSlotCount != 0);
  5990. if (!functionBody->DoStackScopeSlots())
  5991. {
  5992. return this->NewScopeSlots(
  5993. scopeSlotCount + ScopeSlots::FirstSlotIndex, this->GetScriptContext(), (Var)functionBody);
  5994. }
  5995. slotArray = (Var*)this->GetLocalClosure();
  5996. Assert(slotArray != nullptr);
  5997. ScopeSlots scopeSlots(slotArray);
  5998. scopeSlots.SetCount(scopeSlotCount);
  5999. scopeSlots.SetScopeMetadata((Var)functionBody);
  6000. Var undef = functionBody->GetScriptContext()->GetLibrary()->GetUndefined();
  6001. for (unsigned int i = 0; i < scopeSlotCount; i++)
  6002. {
  6003. scopeSlots.Set(i, undef);
  6004. }
  6005. return slotArray;
  6006. }
  6007. Var
  6008. InterpreterStackFrame::NewScopeObject()
  6009. {
  6010. Var scopeObject;
  6011. if (m_functionBody->HasCachedScopePropIds())
  6012. {
  6013. const Js::PropertyIdArray *propIds =
  6014. Js::ByteCodeReader::ReadPropertyIdArray(0, this->GetFunctionBody(), ActivationObjectEx::ExtraSlotCount());
  6015. Var funcExpr = this->GetFunctionExpression();
  6016. PropertyId objectId = ActivationObjectEx::GetLiteralObjectRef(propIds);
  6017. scopeObject = JavascriptOperators::OP_InitCachedScope(funcExpr, propIds,
  6018. this->GetFunctionBody()->GetObjectLiteralTypeRef(objectId),
  6019. propIds->hasNonSimpleParams, GetScriptContext());
  6020. }
  6021. else
  6022. {
  6023. scopeObject = JavascriptOperators::OP_NewScopeObject(GetScriptContext());
  6024. }
  6025. this->SetLocalClosure(scopeObject);
  6026. return scopeObject;
  6027. }
  6028. FrameDisplay *
  6029. InterpreterStackFrame::GetFrameDisplayForNestedFunc() const
  6030. {
  6031. if (this->localFrameDisplay == nullptr)
  6032. {
  6033. return (FrameDisplay*)LdEnv();
  6034. }
  6035. return this->localFrameDisplay;
  6036. }
  6037. template <class T>
  6038. void InterpreterStackFrame::OP_NewStackScFunc(const unaligned T * playout)
  6039. {
  6040. uint funcIndex = playout->SlotIndex;
  6041. FrameDisplay *frameDisplay = this->GetFrameDisplayForNestedFunc();
  6042. SetRegAllowStackVarEnableOnly(playout->Value,
  6043. StackScriptFunction::OP_NewStackScFunc(frameDisplay,
  6044. reinterpret_cast<Js::FunctionProxy**>(this->m_functionBody->GetNestedFuncReference(funcIndex)),
  6045. this->GetStackNestedFunction(funcIndex)));
  6046. }
  6047. template <class T>
  6048. void InterpreterStackFrame::OP_NewInnerStackScFunc(const unaligned T * playout)
  6049. {
  6050. uint funcIndex = playout->SlotIndex;
  6051. FrameDisplay *frameDisplay = (FrameDisplay*)GetNonVarReg(playout->Instance);
  6052. SetRegAllowStackVarEnableOnly(playout->Value,
  6053. StackScriptFunction::OP_NewStackScFunc(frameDisplay,
  6054. reinterpret_cast<Js::FunctionProxy**>(this->m_functionBody->GetNestedFuncReference(funcIndex)),
  6055. this->GetStackNestedFunction(funcIndex)));
  6056. }
  6057. template <class T>
  6058. void InterpreterStackFrame::OP_DeleteFld(const unaligned T * playout)
  6059. {
  6060. Var result = JavascriptOperators::OP_DeleteProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  6061. SetReg(playout->Value, result);
  6062. }
  6063. template <class T>
  6064. void InterpreterStackFrame::OP_DeleteLocalFld(const unaligned T * playout)
  6065. {
  6066. Var result = JavascriptOperators::OP_DeleteProperty(this->localClosure, m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  6067. SetReg(playout->Instance, result);
  6068. }
  6069. template <class T>
  6070. void InterpreterStackFrame::OP_DeleteRootFld(const unaligned T * playout)
  6071. {
  6072. Var result = JavascriptOperators::OP_DeleteRootProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext());
  6073. SetReg(playout->Value, result);
  6074. }
  6075. template <class T>
  6076. void InterpreterStackFrame::OP_DeleteFldStrict(const unaligned T * playout)
  6077. {
  6078. Var result = JavascriptOperators::OP_DeleteProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext(), PropertyOperation_StrictMode);
  6079. SetReg(playout->Value, result);
  6080. }
  6081. template <class T>
  6082. void InterpreterStackFrame::OP_DeleteRootFldStrict(const unaligned T * playout)
  6083. {
  6084. Var result = JavascriptOperators::OP_DeleteRootProperty(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetScriptContext(), PropertyOperation_StrictMode);
  6085. SetReg(playout->Value, result);
  6086. }
  6087. template <typename T>
  6088. void InterpreterStackFrame::OP_ScopedDeleteFld(const unaligned OpLayoutT_ElementScopedC<T> * playout)
  6089. {
  6090. // Implicit root object as default instance
  6091. Var result = JavascriptOperators::OP_DeletePropertyScoped(GetEnvForEvalCode(),
  6092. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  6093. GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
  6094. SetReg(playout->Value, result);
  6095. }
  6096. template <typename T>
  6097. void InterpreterStackFrame::OP_ScopedDeleteFldStrict(const unaligned OpLayoutT_ElementScopedC<T> * playout)
  6098. {
  6099. // Implicit root object as default instance
  6100. Var result = JavascriptOperators::OP_DeletePropertyScoped(GetEnvForEvalCode(),
  6101. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  6102. GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext(), PropertyOperation_StrictMode);
  6103. SetReg(playout->Value, result);
  6104. }
  6105. template <class T>
  6106. void InterpreterStackFrame::OP_ScopedLdInst(const unaligned T * playout)
  6107. {
  6108. Var thisVar;
  6109. Var rootObject = GetFunctionBody()->GetRootObject();
  6110. Var result = JavascriptOperators::OP_GetInstanceScoped(GetEnvForEvalCode(),
  6111. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), rootObject, &thisVar, GetScriptContext());
  6112. SetReg(playout->Value, result);
  6113. SetReg(playout->Value2, thisVar);
  6114. }
  6115. template <typename T>
  6116. void InterpreterStackFrame::OP_ScopedInitFunc(const unaligned OpLayoutT_ElementScopedC<T> * playout)
  6117. {
  6118. JavascriptOperators::OP_InitFuncScoped(GetEnvForEvalCode(),
  6119. m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex),
  6120. GetReg(playout->Value), GetReg(Js::FunctionBody::RootObjectRegSlot), GetScriptContext());
  6121. }
  6122. template <class T>
  6123. void InterpreterStackFrame::OP_ClearAttributes(const unaligned T * playout)
  6124. {
  6125. JavascriptOperators::OP_ClearAttributes(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex));
  6126. }
  6127. template <class T>
  6128. void InterpreterStackFrame::OP_InitGetFld(const unaligned T * playout)
  6129. {
  6130. JavascriptOperators::OP_InitGetter(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
  6131. }
  6132. template <class T>
  6133. void InterpreterStackFrame::OP_InitSetFld(const unaligned T * playout)
  6134. {
  6135. JavascriptOperators::OP_InitSetter(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
  6136. }
  6137. template <class T>
  6138. void InterpreterStackFrame::OP_InitSetElemI(const unaligned T * playout)
  6139. {
  6140. JavascriptOperators::OP_InitElemSetter(
  6141. GetReg(playout->Instance),
  6142. GetReg(playout->Element),
  6143. GetReg(playout->Value),
  6144. m_functionBody->GetScriptContext()
  6145. );
  6146. }
  6147. template <class T>
  6148. void InterpreterStackFrame::OP_InitGetElemI(const unaligned T * playout)
  6149. {
  6150. JavascriptOperators::OP_InitElemGetter(
  6151. GetReg(playout->Instance),
  6152. GetReg(playout->Element),
  6153. GetReg(playout->Value),
  6154. m_functionBody->GetScriptContext()
  6155. );
  6156. }
  6157. template <class T>
  6158. void InterpreterStackFrame::OP_InitComputedProperty(const unaligned T * playout)
  6159. {
  6160. JavascriptOperators::OP_InitComputedProperty(
  6161. GetReg(playout->Instance),
  6162. GetReg(playout->Element),
  6163. GetReg(playout->Value),
  6164. m_functionBody->GetScriptContext()
  6165. );
  6166. }
  6167. template <class T>
  6168. void InterpreterStackFrame::OP_InitProto(const unaligned T * playout)
  6169. {
  6170. JavascriptOperators::OP_InitProto(GetReg(playout->Instance), m_functionBody->GetReferencedPropertyId(playout->PropertyIdIndex), GetReg(playout->Value));
  6171. }
  6172. void InterpreterStackFrame::DoInterruptProbe()
  6173. {
  6174. PROBE_STACK(scriptContext, 0);
  6175. }
  6176. void InterpreterStackFrame::InitializeStackFunctions(StackScriptFunction * scriptFunctions)
  6177. {
  6178. this->stackNestedFunctions = scriptFunctions;
  6179. FunctionBody * functionBody = this->m_functionBody;
  6180. uint nestedCount = functionBody->GetNestedCount();
  6181. for (uint i = 0; i < nestedCount; i++)
  6182. {
  6183. StackScriptFunction * stackScriptFunction = scriptFunctions + i;
  6184. FunctionProxy* nestedProxy = functionBody->GetNestedFunc(i);
  6185. ScriptFunctionType* type = nestedProxy->EnsureDeferredPrototypeType();
  6186. new (stackScriptFunction)StackScriptFunction(nestedProxy, type);
  6187. }
  6188. }
  6189. StackScriptFunction * InterpreterStackFrame::GetStackNestedFunction(uint index)
  6190. {
  6191. Assert(index < this->m_functionBody->GetNestedCount());
  6192. // Re-check if we have disable stack nested function
  6193. if (this->m_functionBody->DoStackNestedFunc())
  6194. {
  6195. return this->stackNestedFunctions + index;
  6196. }
  6197. return nullptr;
  6198. }
  6199. void InterpreterStackFrame::SetExecutingStackFunction(ScriptFunction * scriptFunction)
  6200. {
  6201. Assert(ThreadContext::IsOnStack(this->function));
  6202. Assert(this->m_functionBody == scriptFunction->GetFunctionBody());
  6203. this->function = scriptFunction;
  6204. }
  6205. DWORD_PTR InterpreterStackFrame::GetStackAddress() const
  6206. {
  6207. return m_stackAddress;
  6208. }
  6209. void* InterpreterStackFrame::GetAddressOfReturnAddress() const
  6210. {
  6211. return this->addressOfReturnAddress;
  6212. }
  6213. template <class T>
  6214. const byte * InterpreterStackFrame::OP_Br(const unaligned T * playout)
  6215. {
  6216. return m_reader.SetCurrentRelativeOffset((const byte *)(playout + 1), playout->RelativeJumpOffset);
  6217. }
  6218. template <class T>
  6219. void InterpreterStackFrame::OP_InitClass(const unaligned OpLayoutT_Class<T> * playout)
  6220. {
  6221. JavascriptOperators::OP_InitClass(GetReg(playout->Constructor), playout->Extends != Js::Constants::NoRegister ? GetReg(playout->Extends) : NULL, GetScriptContext());
  6222. }
  6223. template <class T>
  6224. void InterpreterStackFrame::OP_EmitTmpRegCount(const unaligned OpLayoutT_Unsigned1<T> * playout)
  6225. {
  6226. this->scriptContext->GetDebugContext()->GetProbeContainer()->SetCurrentTmpRegCount(playout->C1);
  6227. }
  6228. Var InterpreterStackFrame::OP_LdSuper(ScriptContext * scriptContext)
  6229. {
  6230. return JavascriptOperators::OP_LdSuper(function, scriptContext);
  6231. }
  6232. Var InterpreterStackFrame::OP_LdSuperCtor(ScriptContext * scriptContext)
  6233. {
  6234. return JavascriptOperators::OP_LdSuperCtor(function, scriptContext);
  6235. }
  6236. Var InterpreterStackFrame::OP_ScopedLdSuper(ScriptContext * scriptContext)
  6237. {
  6238. return JavascriptOperators::OP_ScopedLdSuper(function, scriptContext);
  6239. }
  6240. Var InterpreterStackFrame::OP_ScopedLdSuperCtor(ScriptContext * scriptContext)
  6241. {
  6242. return JavascriptOperators::OP_ScopedLdSuperCtor(function, scriptContext);
  6243. }
  6244. void InterpreterStackFrame::ValidateRegValue(Var value, bool allowStackVar, bool allowStackVarOnDisabledStackNestedFunc) const
  6245. {
  6246. #if DBG
  6247. if (value != nullptr && !TaggedNumber::Is(value))
  6248. {
  6249. if (!allowStackVar || !this->m_functionBody->DoStackNestedFunc())
  6250. {
  6251. Assert(!ThreadContext::IsOnStack(value)
  6252. || (allowStackVar && allowStackVarOnDisabledStackNestedFunc && StackScriptFunction::IsBoxed(value)));
  6253. }
  6254. Assert(!CrossSite::NeedMarshalVar(value, GetScriptContext()));
  6255. }
  6256. #endif
  6257. }
  6258. template <typename RegSlotType>
  6259. Var InterpreterStackFrame::GetReg(RegSlotType localRegisterID) const
  6260. {
  6261. Var value = m_localSlots[localRegisterID];
  6262. ValidateRegValue(value);
  6263. return value;
  6264. }
  6265. template <typename RegSlotType>
  6266. void InterpreterStackFrame::SetReg(RegSlotType localRegisterID, Var value)
  6267. {
  6268. Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
  6269. ValidateRegValue(value);
  6270. m_localSlots[localRegisterID] = value;
  6271. }
  6272. template <typename T>
  6273. T InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6274. {
  6275. return (T)m_localIntSlots[localRegisterID];
  6276. }
  6277. // specialized version for doubles
  6278. template <>
  6279. double InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6280. {
  6281. return (double)m_localDoubleSlots[localRegisterID];
  6282. }
  6283. template <>
  6284. float InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6285. {
  6286. return (float)m_localFloatSlots[localRegisterID];
  6287. }
  6288. template <typename T>
  6289. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, T bValue)
  6290. {
  6291. m_localIntSlots[localRegisterID] = (int)bValue;
  6292. }
  6293. template <>
  6294. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, float bValue)
  6295. {
  6296. m_localFloatSlots[localRegisterID] = (float)bValue;
  6297. }
  6298. template <>
  6299. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, double bValue)
  6300. {
  6301. m_localDoubleSlots[localRegisterID] = bValue;
  6302. }
  6303. template <typename RegSlotType>
  6304. int InterpreterStackFrame::GetRegRawInt(RegSlotType localRegisterID) const
  6305. {
  6306. return m_localIntSlots[localRegisterID];
  6307. }
  6308. template <typename RegSlotType>
  6309. double InterpreterStackFrame::GetRegRawDouble(RegSlotType localRegisterID) const
  6310. {
  6311. return m_localDoubleSlots[localRegisterID];
  6312. }
  6313. template <typename RegSlotType>
  6314. float InterpreterStackFrame::GetRegRawFloat(RegSlotType localRegisterID) const
  6315. {
  6316. return m_localFloatSlots[localRegisterID];
  6317. }
  6318. template <typename RegSlotType>
  6319. void InterpreterStackFrame::SetRegRawInt(RegSlotType localRegisterID, int bValue)
  6320. {
  6321. m_localIntSlots[localRegisterID] = bValue;
  6322. }
  6323. template <typename RegSlotType>
  6324. void InterpreterStackFrame::SetRegRawDouble(RegSlotType localRegisterID, double bValue)
  6325. {
  6326. m_localDoubleSlots[localRegisterID] = bValue;
  6327. }
  6328. template <typename RegSlotType>
  6329. void InterpreterStackFrame::SetRegRawFloat(RegSlotType localRegisterID, float bValue)
  6330. {
  6331. m_localFloatSlots[localRegisterID] = bValue;
  6332. }
  6333. template <typename RegSlotType>
  6334. Var InterpreterStackFrame::GetRegAllowStackVar(RegSlotType localRegisterID) const
  6335. {
  6336. Var value = m_localSlots[localRegisterID];
  6337. ValidateRegValue(value, true);
  6338. return value;
  6339. }
  6340. template <typename RegSlotType>
  6341. void InterpreterStackFrame::SetRegAllowStackVar(RegSlotType localRegisterID, Var value)
  6342. {
  6343. Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
  6344. ValidateRegValue(value, true);
  6345. m_localSlots[localRegisterID] = value;
  6346. }
  6347. template <typename RegSlotType>
  6348. Var InterpreterStackFrame::GetRegAllowStackVarEnableOnly(RegSlotType localRegisterID) const
  6349. {
  6350. Var value = m_localSlots[localRegisterID];
  6351. ValidateRegValue(value, true, false);
  6352. return value;
  6353. }
  6354. template <typename RegSlotType>
  6355. void InterpreterStackFrame::SetRegAllowStackVarEnableOnly(RegSlotType localRegisterID, Var value)
  6356. {
  6357. Assert(localRegisterID == 0 || localRegisterID >= m_functionBody->GetConstantCount());
  6358. ValidateRegValue(value, true, false);
  6359. m_localSlots[localRegisterID] = value;
  6360. }
  6361. template <>
  6362. AsmJsSIMDValue InterpreterStackFrame::GetRegRaw(RegSlot localRegisterID) const
  6363. {
  6364. return (AsmJsSIMDValue)m_localSimdSlots[localRegisterID];
  6365. }
  6366. template<>
  6367. void InterpreterStackFrame::SetRegRaw(RegSlot localRegisterID, AsmJsSIMDValue bValue)
  6368. {
  6369. m_localSimdSlots[localRegisterID] = bValue;
  6370. }
  6371. template <typename RegSlotType>
  6372. AsmJsSIMDValue InterpreterStackFrame::GetRegRawSimd(RegSlotType localRegisterID) const
  6373. {
  6374. return m_localSimdSlots[localRegisterID];
  6375. }
  6376. template <typename RegSlotType>
  6377. void InterpreterStackFrame::SetRegRawSimd(RegSlotType localRegisterID, AsmJsSIMDValue bValue)
  6378. {
  6379. m_localSimdSlots[localRegisterID] = bValue;
  6380. }
  6381. template <class T>
  6382. void InterpreterStackFrame::OP_SimdLdArrGeneric(const unaligned T* playout)
  6383. {
  6384. Assert(playout->ViewType < 8);
  6385. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & TypedArrayViewMask[playout->ViewType];
  6386. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6387. BYTE* buffer = arr->GetBuffer();
  6388. uint8 dataWidth = playout->DataWidth;
  6389. RegSlot dstReg = playout->Value;
  6390. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6391. {
  6392. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, L"Simd typed array access");
  6393. }
  6394. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6395. AsmJsSIMDValue value;
  6396. value = SIMDLdData(data, dataWidth);
  6397. SetRegRawSimd(dstReg, value);
  6398. }
  6399. template <class T>
  6400. void InterpreterStackFrame::OP_SimdLdArrConstIndex(const unaligned T* playout)
  6401. {
  6402. Assert(playout->ViewType < 8);
  6403. const uint32 index = playout->SlotIndex;
  6404. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6405. BYTE* buffer = arr->GetBuffer();
  6406. uint8 dataWidth = playout->DataWidth;
  6407. RegSlot dstReg = playout->Value;
  6408. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6409. {
  6410. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, L"Simd typed array access");
  6411. }
  6412. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6413. AsmJsSIMDValue value;
  6414. value = SIMDLdData(data, dataWidth);
  6415. SetRegRawSimd(dstReg, value);
  6416. }
  6417. template <class T>
  6418. void InterpreterStackFrame::OP_SimdStArrGeneric(const unaligned T* playout)
  6419. {
  6420. Assert(playout->ViewType < 8);
  6421. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & TypedArrayViewMask[playout->ViewType];
  6422. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6423. BYTE* buffer = arr->GetBuffer();
  6424. uint8 dataWidth = playout->DataWidth;
  6425. RegSlot srcReg = playout->Value;
  6426. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6427. {
  6428. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, L"Simd typed array access");
  6429. }
  6430. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6431. AsmJsSIMDValue value = GetRegRawSimd(srcReg);
  6432. SIMDStData(data, value, dataWidth);
  6433. }
  6434. template <class T>
  6435. void InterpreterStackFrame::OP_SimdStArrConstIndex(const unaligned T* playout)
  6436. {
  6437. Assert(playout->ViewType < 8);
  6438. const uint32 index = playout->SlotIndex;
  6439. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6440. BYTE* buffer = arr->GetBuffer();
  6441. uint8 dataWidth = playout->DataWidth;
  6442. RegSlot srcReg = playout->Value;
  6443. if (index < 0 || index + dataWidth > arr->GetByteLength())
  6444. {
  6445. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange, L"Simd typed array access");
  6446. }
  6447. AsmJsSIMDValue *data = (AsmJsSIMDValue*)(buffer + index);
  6448. AsmJsSIMDValue value = GetRegRawSimd(srcReg);
  6449. SIMDStData(data, value, dataWidth);
  6450. }
  6451. Var InterpreterStackFrame::GetNonVarReg(RegSlot localRegisterID) const
  6452. {
  6453. return m_localSlots[localRegisterID];
  6454. }
  6455. void InterpreterStackFrame::SetNonVarReg(RegSlot localRegisterID, Var aValue)
  6456. {
  6457. m_localSlots[localRegisterID] = aValue;
  6458. }
  6459. Var InterpreterStackFrame::GetRootObject() const
  6460. {
  6461. Var rootObject = GetReg(Js::FunctionBody::RootObjectRegSlot);
  6462. Assert(rootObject == this->GetFunctionBody()->LoadRootObject());
  6463. return rootObject;
  6464. }
  6465. Var InterpreterStackFrame::OP_ArgIn0()
  6466. {
  6467. return m_inParams[0];
  6468. }
  6469. #if ENABLE_PROFILE_INFO
  6470. template <class T>
  6471. void InterpreterStackFrame::OP_ProfiledArgOut_A(const unaligned T * playout)
  6472. {
  6473. FunctionBody* functionBody = this->m_functionBody;
  6474. DynamicProfileInfo * dynamicProfileInfo = functionBody->GetDynamicProfileInfo();
  6475. Assert(playout->Reg > FunctionBody::FirstRegSlot && playout->Reg < functionBody->GetConstantCount());
  6476. Var value = GetReg(playout->Reg);
  6477. if (value != nullptr && TaggedInt::Is(value))
  6478. {
  6479. dynamicProfileInfo->RecordConstParameterAtCallSite(playout->profileId, playout->Arg);
  6480. }
  6481. SetOut(playout->Arg, GetReg(playout->Reg));
  6482. }
  6483. #endif
  6484. template <class T>
  6485. void InterpreterStackFrame::OP_ArgOut_A(const unaligned T * playout)
  6486. {
  6487. SetOut(playout->Arg, GetReg(playout->Reg));
  6488. }
  6489. #if DBG
  6490. template <class T>
  6491. void InterpreterStackFrame::OP_ArgOut_ANonVar(const unaligned T * playout)
  6492. {
  6493. SetOut(playout->Arg, GetNonVarReg(playout->Reg));
  6494. }
  6495. #endif
  6496. template <class T>
  6497. void InterpreterStackFrame::OP_ArgOut_Env(const unaligned T * playout)
  6498. {
  6499. Var argEnv;
  6500. if (this->m_functionBody->GetLocalFrameDisplayReg() != Constants::NoRegister)
  6501. {
  6502. argEnv = this->GetLocalFrameDisplay();
  6503. }
  6504. else
  6505. {
  6506. argEnv = this->LdEnv();
  6507. }
  6508. SetOut(playout->Arg, argEnv);
  6509. }
  6510. BOOL InterpreterStackFrame::OP_BrFalse_A(Var aValue, ScriptContext* scriptContext)
  6511. {
  6512. return !JavascriptConversion::ToBoolean(aValue, scriptContext);
  6513. }
  6514. BOOL InterpreterStackFrame::OP_BrTrue_A(Var aValue, ScriptContext* scriptContext)
  6515. {
  6516. return JavascriptConversion::ToBoolean(aValue, scriptContext);
  6517. }
  6518. BOOL InterpreterStackFrame::OP_BrNotNull_A(Var aValue)
  6519. {
  6520. return aValue != NULL;
  6521. }
  6522. BOOL InterpreterStackFrame::OP_BrUndecl_A(Var aValue)
  6523. {
  6524. return this->scriptContext->GetLibrary()->IsUndeclBlockVar(aValue);
  6525. }
  6526. BOOL InterpreterStackFrame::OP_BrNotUndecl_A(Var aValue)
  6527. {
  6528. return !this->scriptContext->GetLibrary()->IsUndeclBlockVar(aValue);
  6529. }
  6530. BOOL InterpreterStackFrame::OP_BrOnHasProperty(Var argInstance, uint propertyIdIndex, ScriptContext* scriptContext)
  6531. {
  6532. return JavascriptOperators::OP_HasProperty(argInstance,
  6533. this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
  6534. }
  6535. BOOL InterpreterStackFrame::OP_BrOnNoProperty(Var argInstance, uint propertyIdIndex, ScriptContext* scriptContext)
  6536. {
  6537. return !JavascriptOperators::OP_HasProperty(argInstance,
  6538. this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
  6539. }
  6540. BOOL InterpreterStackFrame::OP_BrOnNoEnvProperty(Var envInstance, int32 slotIndex, uint propertyIdIndex, ScriptContext* scriptContext)
  6541. {
  6542. Var instance = OP_LdFrameDisplaySlot(envInstance, slotIndex);
  6543. return !JavascriptOperators::OP_HasProperty(instance,
  6544. this->m_functionBody->GetReferencedPropertyId(propertyIdIndex), scriptContext);
  6545. }
  6546. BOOL InterpreterStackFrame::OP_BrOnClassConstructor(Var aValue)
  6547. {
  6548. return JavascriptOperators::IsClassConstructor(aValue);
  6549. }
  6550. template<class T>
  6551. void InterpreterStackFrame::OP_LdLen(const unaligned T * const playout)
  6552. {
  6553. Assert(playout);
  6554. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  6555. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  6556. threadContext->ClearImplicitCallFlags();
  6557. const auto instance = GetReg(playout->R1);
  6558. Var length = JavascriptOperators::OP_GetLength(instance, GetScriptContext());
  6559. threadContext->CheckAndResetImplicitCallAccessorFlag();
  6560. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  6561. SetReg(playout->R0, length);
  6562. }
  6563. #if ENABLE_PROFILE_INFO
  6564. template<class T>
  6565. void InterpreterStackFrame::OP_ProfiledLdLen(const unaligned OpLayoutDynamicProfile<T> *const playout)
  6566. {
  6567. Assert(playout);
  6568. const auto functionBody = m_functionBody;
  6569. const auto profileData = functionBody->GetDynamicProfileInfo();
  6570. const auto instance = GetReg(playout->R1);
  6571. LdElemInfo ldElemInfo;
  6572. ldElemInfo.arrayType = ValueType::Uninitialized.Merge(instance);
  6573. ThreadContext* threadContext = this->GetScriptContext()->GetThreadContext();
  6574. ImplicitCallFlags savedImplicitCallFlags = threadContext->GetImplicitCallFlags();
  6575. threadContext->ClearImplicitCallFlags();
  6576. Var length = JavascriptOperators::OP_GetLength(instance, GetScriptContext());
  6577. threadContext->CheckAndResetImplicitCallAccessorFlag();
  6578. threadContext->AddImplicitCallFlags(savedImplicitCallFlags);
  6579. ldElemInfo.elemType = ldElemInfo.elemType.Merge(length);
  6580. profileData->RecordElementLoad(functionBody, playout->profileId, ldElemInfo);
  6581. SetReg(playout->R0, length);
  6582. }
  6583. #endif
  6584. Var InterpreterStackFrame::GetFunctionExpression()
  6585. {
  6586. // Make sure we get the boxed function object if is there, (or the function itself)
  6587. return StackScriptFunction::GetCurrentFunctionObject(this->function->GetRealFunctionObject());
  6588. }
  6589. template <class T>
  6590. void InterpreterStackFrame::OP_LdFunctionExpression(const unaligned T * playout)
  6591. {
  6592. SetRegAllowStackVar(playout->R0, this->GetFunctionExpression());
  6593. }
  6594. template <class T>
  6595. void InterpreterStackFrame::OP_StFunctionExpression(const unaligned T * playout)
  6596. {
  6597. OP_StFunctionExpression(GetReg(playout->Instance), GetReg(playout->Value), playout->PropertyIdIndex);
  6598. }
  6599. template <class T>
  6600. void InterpreterStackFrame::OP_StLocalFunctionExpression(const unaligned T * playout)
  6601. {
  6602. OP_StFunctionExpression(this->localClosure, GetReg(playout->Instance), playout->PropertyIdIndex);
  6603. }
  6604. void InterpreterStackFrame::OP_StFunctionExpression(Var instance, Var value, PropertyIdIndexType index)
  6605. {
  6606. JavascriptOperators::OP_StFunctionExpression(instance,
  6607. this->m_functionBody->GetReferencedPropertyId(index), value);
  6608. }
  6609. template <class T>
  6610. void InterpreterStackFrame::OP_LdNewTarget(const unaligned T* playout)
  6611. {
  6612. if (this->m_callFlags & CallFlags_NewTarget)
  6613. {
  6614. SetRegAllowStackVar(playout->R0, (Js::RecyclableObject*)this->m_inParams[this->m_inSlotsCount]);
  6615. }
  6616. else if (this->m_callFlags & CallFlags_New)
  6617. {
  6618. SetRegAllowStackVar(playout->R0, this->GetFunctionExpression());
  6619. }
  6620. else
  6621. {
  6622. SetReg(playout->R0, this->GetScriptContext()->GetLibrary()->GetUndefined());
  6623. }
  6624. }
  6625. Var InterpreterStackFrame::OP_Ld_A(Var aValue)
  6626. {
  6627. return aValue;
  6628. }
  6629. Var InterpreterStackFrame::LdEnv() const
  6630. {
  6631. return this->function->GetEnvironment();
  6632. }
  6633. void InterpreterStackFrame::SetEnv(FrameDisplay *frameDisplay)
  6634. {
  6635. this->function->SetEnvironment(frameDisplay);
  6636. }
  6637. Var InterpreterStackFrame::OP_LdLocalObj()
  6638. {
  6639. if (!VirtualTableInfo<ActivationObject>::HasVirtualTable(this->localClosure) &&
  6640. !VirtualTableInfo<ActivationObjectEx>::HasVirtualTable(this->localClosure))
  6641. {
  6642. Js::Throw::FatalInternalError();
  6643. }
  6644. return this->localClosure;
  6645. }
  6646. #ifndef TEMP_DISABLE_ASMJS
  6647. template <typename T2>
  6648. void InterpreterStackFrame::OP_StArr(uint32 index, RegSlot value)
  6649. {
  6650. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6651. if (index < (arr->GetByteLength()))
  6652. {
  6653. BYTE* buffer = arr->GetBuffer();
  6654. *(T2*)(buffer + index) = (T2)GetRegRaw<T2>(value);
  6655. }
  6656. }
  6657. #endif
  6658. template<> inline double InterpreterStackFrame::GetArrayViewOverflowVal()
  6659. {
  6660. return *(double*)&NumberConstants::k_Nan;
  6661. }
  6662. template<> inline float InterpreterStackFrame::GetArrayViewOverflowVal()
  6663. {
  6664. return (float)*(double*)&NumberConstants::k_Nan;
  6665. }
  6666. template<typename T> T InterpreterStackFrame::GetArrayViewOverflowVal()
  6667. {
  6668. return 0;
  6669. }
  6670. template <class T>
  6671. void InterpreterStackFrame::OP_LdArrFunc(const unaligned T* playout)
  6672. {
  6673. Var* arr = (Var*)GetNonVarReg(playout->Instance);
  6674. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex);
  6675. m_localSlots[playout->Value] = arr[index];
  6676. }
  6677. #ifndef TEMP_DISABLE_ASMJS
  6678. template <typename T2>
  6679. void InterpreterStackFrame::OP_LdArr(uint32 index, RegSlot value)
  6680. {
  6681. JavascriptArrayBuffer* arr = *(JavascriptArrayBuffer**)GetNonVarReg(AsmJsFunctionMemory::ArrayBufferRegister);
  6682. BYTE* buffer = arr->GetBuffer();
  6683. T2 val = index < (arr->GetByteLength()) ? *(T2*)(buffer + index) : GetArrayViewOverflowVal<T2>();
  6684. SetRegRaw<T2>(value, val);
  6685. }
  6686. #endif
  6687. template <class T, typename T2>
  6688. void InterpreterStackFrame::OP_StSlotPrimitive(const unaligned T* playout)
  6689. {
  6690. T2* buffer = (T2*)GetNonVarReg(playout->Instance);
  6691. buffer[playout->SlotIndex] = GetRegRaw<T2>(playout->Value);
  6692. }
  6693. template <class T>
  6694. Var InterpreterStackFrame::OP_LdAsmJsSlot(Var instance, const unaligned T* playout)
  6695. {
  6696. return ((Var*)instance)[playout->SlotIndex];
  6697. }
  6698. template <class T, typename T2>
  6699. void InterpreterStackFrame::OP_LdSlotPrimitive(const unaligned T* playout)
  6700. {
  6701. T2* buffer = (T2*)GetNonVarReg(playout->Instance);
  6702. SetRegRaw<T2>(playout->Value, buffer[playout->SlotIndex]);
  6703. }
  6704. template <class T>
  6705. void InterpreterStackFrame::OP_LdArrGeneric(const unaligned T* playout)
  6706. {
  6707. Assert(playout->ViewType < 8);
  6708. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & TypedArrayViewMask[playout->ViewType];
  6709. (this->*LdArrFunc[playout->ViewType])(index, playout->Value);
  6710. }
  6711. template <class T>
  6712. void InterpreterStackFrame::OP_LdArrConstIndex(const unaligned T* playout)
  6713. {
  6714. const uint32 index = playout->SlotIndex;
  6715. Assert(playout->ViewType < 8);
  6716. (this->*LdArrFunc[playout->ViewType])(index, playout->Value);
  6717. }
  6718. template <class T>
  6719. void InterpreterStackFrame::OP_StArrGeneric(const unaligned T* playout)
  6720. {
  6721. Assert(playout->ViewType < 8);
  6722. const uint32 index = (uint32)GetRegRawInt(playout->SlotIndex) & TypedArrayViewMask[playout->ViewType];
  6723. (this->*StArrFunc[playout->ViewType])(index, playout->Value);
  6724. }
  6725. template <class T>
  6726. void InterpreterStackFrame::OP_StArrConstIndex(const unaligned T* playout)
  6727. {
  6728. const uint32 index = playout->SlotIndex;
  6729. Assert(playout->ViewType < 8);
  6730. (this->*StArrFunc[playout->ViewType])(index, playout->Value);
  6731. }
  6732. Var InterpreterStackFrame::OP_LdSlot(Var instance, int32 slotIndex)
  6733. {
  6734. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  6735. {
  6736. if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
  6737. {
  6738. Js::Throw::FatalInternalError();
  6739. }
  6740. }
  6741. return ((Var*)(instance))[slotIndex];
  6742. }
  6743. template <class T>
  6744. Var InterpreterStackFrame::OP_LdSlot(Var instance, const unaligned T* playout)
  6745. {
  6746. return OP_LdSlot(instance, playout->SlotIndex);
  6747. }
  6748. #if ENABLE_PROFILE_INFO
  6749. template <class T>
  6750. Var InterpreterStackFrame::OP_ProfiledLdSlot(Var instance, const unaligned T* playout)
  6751. {
  6752. Var value = OP_LdSlot(instance, playout->SlotIndex);
  6753. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  6754. return value;
  6755. }
  6756. #endif
  6757. template <class T>
  6758. Var InterpreterStackFrame::OP_LdInnerSlot(Var slotArray, const unaligned T* playout)
  6759. {
  6760. return OP_LdSlot(slotArray, playout->SlotIndex2);
  6761. }
  6762. #if ENABLE_PROFILE_INFO
  6763. template <class T>
  6764. Var InterpreterStackFrame::OP_ProfiledLdInnerSlot(Var slotArray, const unaligned T* playout)
  6765. {
  6766. Var value = OP_LdInnerSlot(slotArray, playout);
  6767. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  6768. return value;
  6769. }
  6770. #endif
  6771. template <class T>
  6772. Var InterpreterStackFrame::OP_LdInnerObjSlot(Var slotArray, const unaligned T* playout)
  6773. {
  6774. return OP_LdObjSlot(slotArray, playout->SlotIndex2);
  6775. }
  6776. #if ENABLE_PROFILE_INFO
  6777. template <class T>
  6778. Var InterpreterStackFrame::OP_ProfiledLdInnerObjSlot(Var slotArray, const unaligned T* playout)
  6779. {
  6780. Var value = OP_LdInnerObjSlot(slotArray, playout);
  6781. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  6782. return value;
  6783. }
  6784. #endif
  6785. Var InterpreterStackFrame::OP_LdFrameDisplaySlot(Var instance, int32 slotIndex)
  6786. {
  6787. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  6788. {
  6789. if (((FrameDisplay*)instance)->GetLength() < slotIndex - Js::FrameDisplay::GetOffsetOfScopes()/sizeof(Var))
  6790. {
  6791. Js::Throw::FatalInternalError();
  6792. }
  6793. }
  6794. return ((Var*)instance)[slotIndex];
  6795. }
  6796. template <class T>
  6797. Var InterpreterStackFrame::OP_LdEnvObj(Var instance, const unaligned T* playout)
  6798. {
  6799. return OP_LdFrameDisplaySlot(instance, playout->SlotIndex);
  6800. }
  6801. template <class T>
  6802. Var InterpreterStackFrame::OP_LdEnvSlot(Var instance, const unaligned T* playout)
  6803. {
  6804. Var slotArray = OP_LdFrameDisplaySlot(instance, playout->SlotIndex1);
  6805. return OP_LdSlot(slotArray, playout->SlotIndex2);
  6806. }
  6807. #if ENABLE_PROFILE_INFO
  6808. template <class T>
  6809. Var InterpreterStackFrame::OP_ProfiledLdEnvSlot(Var instance, const unaligned T* playout)
  6810. {
  6811. Var value = OP_LdEnvSlot(instance, playout);
  6812. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  6813. return value;
  6814. }
  6815. #endif
  6816. Var InterpreterStackFrame::OP_LdObjSlot(Var instance, int32 slotIndex)
  6817. {
  6818. Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
  6819. return slotArray[slotIndex];
  6820. }
  6821. template <class T>
  6822. Var InterpreterStackFrame::OP_LdObjSlot(Var instance, const unaligned T* playout)
  6823. {
  6824. return OP_LdObjSlot(instance, playout->SlotIndex);
  6825. }
  6826. #if ENABLE_PROFILE_INFO
  6827. template <class T>
  6828. Var InterpreterStackFrame::OP_ProfiledLdObjSlot(Var instance, const unaligned T* playout)
  6829. {
  6830. Var value = OP_LdObjSlot(instance, playout->SlotIndex);
  6831. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  6832. return value;
  6833. }
  6834. #endif
  6835. template <class T>
  6836. Var InterpreterStackFrame::OP_LdEnvObjSlot(Var instance, const unaligned T* playout)
  6837. {
  6838. Var slotArray = OP_LdFrameDisplaySlot(instance, playout->SlotIndex1);
  6839. return OP_LdObjSlot(slotArray, playout->SlotIndex2);
  6840. }
  6841. #if ENABLE_PROFILE_INFO
  6842. template <class T>
  6843. Var InterpreterStackFrame::OP_ProfiledLdEnvObjSlot(Var instance, const unaligned T* playout)
  6844. {
  6845. Var value = OP_LdEnvObjSlot(instance, playout);
  6846. ProfilingHelpers::ProfileLdSlot(value, GetFunctionBody(), playout->profileId);
  6847. return value;
  6848. }
  6849. #endif
  6850. void InterpreterStackFrame::OP_StSlot(Var instance, int32 slotIndex, Var value)
  6851. {
  6852. // We emit OpCode::StSlot in the bytecode only for scope slot arrays, which are not recyclable objects.
  6853. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  6854. {
  6855. if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
  6856. {
  6857. Js::Throw::FatalInternalError();
  6858. }
  6859. }
  6860. ((Var*)(instance))[slotIndex] = value;
  6861. }
  6862. void InterpreterStackFrame::OP_StEnvSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  6863. {
  6864. Var slotArray = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  6865. OP_StSlot(slotArray, slotIndex2, value);
  6866. }
  6867. void InterpreterStackFrame::OP_StSlotChkUndecl(Var instance, int32 slotIndex, Var value)
  6868. {
  6869. // We emit OpCode::StSlot in the bytecode only for scope slot arrays, which are not recyclable objects.
  6870. if (!PHASE_OFF(ClosureRangeCheckPhase, this->m_functionBody))
  6871. {
  6872. if ((uintptr_t)((Var*)instance)[ScopeSlots::EncodedSlotCountSlotIndex] <= (uintptr_t)(slotIndex - ScopeSlots::FirstSlotIndex))
  6873. {
  6874. Js::Throw::FatalInternalError();
  6875. }
  6876. }
  6877. OP_ChkUndecl(((Var*)instance)[slotIndex]);
  6878. ((Var*)(instance))[slotIndex] = value;
  6879. }
  6880. void InterpreterStackFrame::OP_StEnvSlotChkUndecl(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  6881. {
  6882. Var slotArray = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  6883. OP_StSlotChkUndecl(slotArray, slotIndex2, value);
  6884. }
  6885. void InterpreterStackFrame::OP_StObjSlot(Var instance, int32 slotIndex, Var value)
  6886. {
  6887. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  6888. Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
  6889. slotArray[slotIndex] = value;
  6890. }
  6891. void InterpreterStackFrame::OP_StObjSlotChkUndecl(Var instance, int32 slotIndex, Var value)
  6892. {
  6893. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  6894. Var *slotArray = *(Var**)((char*)instance + DynamicObject::GetOffsetOfAuxSlots());
  6895. OP_ChkUndecl(slotArray[slotIndex]);
  6896. slotArray[slotIndex] = value;
  6897. }
  6898. void InterpreterStackFrame::OP_StEnvObjSlot(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  6899. {
  6900. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  6901. Var envInstance = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  6902. OP_StObjSlot(envInstance, slotIndex2, value);
  6903. }
  6904. void InterpreterStackFrame::OP_StEnvObjSlotChkUndecl(Var instance, int32 slotIndex1, int32 slotIndex2, Var value)
  6905. {
  6906. // It would be nice to assert that it's ok to store directly to slot, but we don't have the propertyId.
  6907. Var envInstance = (Var*)OP_LdFrameDisplaySlot(instance, slotIndex1);
  6908. OP_StObjSlotChkUndecl(envInstance, slotIndex2, value);
  6909. }
  6910. Var InterpreterStackFrame::OP_LdStackArgPtr(void)
  6911. {
  6912. // Return the address of the first param after "this".
  6913. return m_inParams + 1;
  6914. }
  6915. // Called for the debug purpose, to create the arguments object explicitly even though script has not declared it.
  6916. Var InterpreterStackFrame::CreateHeapArguments(ScriptContext* scriptContext)
  6917. {
  6918. return JavascriptOperators::LoadHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, &this->m_inParams[1], scriptContext->GetLibrary()->GetNull(), (PropertyId*)scriptContext->GetLibrary()->GetNull(), scriptContext, false);
  6919. }
  6920. template <bool letArgs>
  6921. Var InterpreterStackFrame::LdHeapArgumentsImpl(Var argsArray, ScriptContext* scriptContext)
  6922. {
  6923. Var frameObj;
  6924. if (m_functionBody->HasScopeObject() && argsArray != scriptContext->GetLibrary()->GetNull())
  6925. {
  6926. frameObj = this->localClosure;
  6927. Assert(frameObj);
  6928. }
  6929. else
  6930. {
  6931. frameObj = scriptContext->GetLibrary()->GetNull();
  6932. }
  6933. Var args = JavascriptOperators::LoadHeapArguments(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, &this->m_inParams[1], frameObj, (PropertyId*)argsArray, scriptContext, letArgs);
  6934. this->m_arguments = args;
  6935. return args;
  6936. }
  6937. Var InterpreterStackFrame::OP_LdHeapArguments(Var argsArray, ScriptContext* scriptContext)
  6938. {
  6939. return LdHeapArgumentsImpl<false>(argsArray, scriptContext);
  6940. }
  6941. Var InterpreterStackFrame::OP_LdLetHeapArguments(Var argsArray, ScriptContext* scriptContext)
  6942. {
  6943. return LdHeapArgumentsImpl<true>(argsArray, scriptContext);
  6944. }
  6945. Var InterpreterStackFrame::OP_LdHeapArgsCached(ScriptContext* scriptContext)
  6946. {
  6947. uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
  6948. Var args = JavascriptOperators::LoadHeapArgsCached(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, &this->m_inParams[1], this->localClosure, scriptContext, false);
  6949. this->m_arguments = args;
  6950. return args;
  6951. }
  6952. Var InterpreterStackFrame::OP_LdLetHeapArgsCached(ScriptContext* scriptContext)
  6953. {
  6954. uint32 formalsCount = this->m_functionBody->GetInParamsCount() - 1;
  6955. Var args = JavascriptOperators::LoadHeapArgsCached(this->function->GetRealFunctionObject(), this->m_inSlotsCount - 1, formalsCount, &this->m_inParams[1], this->localClosure, scriptContext, true);
  6956. this->m_arguments = args;
  6957. return args;
  6958. }
  6959. Var InterpreterStackFrame::OP_LdArgumentsFromFrame()
  6960. {
  6961. return this->m_arguments;
  6962. }
  6963. void* InterpreterStackFrame::OP_LdArgCnt()
  6964. {
  6965. return (void*)m_inSlotsCount;
  6966. }
  6967. Var InterpreterStackFrame::OP_ResumeYield(Var yieldDataVar, RegSlot yieldStarIterator)
  6968. {
  6969. ResumeYieldData* yieldData = static_cast<ResumeYieldData*>(yieldDataVar);
  6970. RecyclableObject* iterator = yieldStarIterator != Constants::NoRegister ? RecyclableObject::FromVar(GetNonVarReg(yieldStarIterator)) : nullptr;
  6971. return JavascriptOperators::OP_ResumeYield(yieldData, iterator);
  6972. }
  6973. void* InterpreterStackFrame::operator new(size_t byteSize, void* previousAllocation)
  6974. {
  6975. //
  6976. // Placement 'new' is used by InterpreterStackFrame to initialize the C++ object on the RcInterpreter's
  6977. // program stack:
  6978. // - Unlike most other allocations, the previously allocated memory will __not__ be
  6979. // zero-initialized, as we do not want the overhead of zero-initializing the frame when
  6980. // calling functions.
  6981. //
  6982. // NOTE: If we wanted to add C# semantics of all locals are automatically zero-initialized,
  6983. // need to determine the most efficient mechanism for this.
  6984. //
  6985. return previousAllocation;
  6986. }
  6987. void __cdecl InterpreterStackFrame::operator delete(void * allocationToFree, void * previousAllocation)
  6988. {
  6989. AssertMsg(allocationToFree == previousAllocation, "Memory locations should match");
  6990. AssertMsg(false, "This function should never actually be called");
  6991. }
  6992. } // namespace Js
  6993. // Make sure the macro and the layout for the op is consistent
  6994. #define DEF2(x, op, ...) \
  6995. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  6996. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  6997. #define DEF3(x, op, ...) DEF2(x, op)
  6998. #define EXDEF2(x, op, ...) \
  6999. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7000. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7001. #define EXDEF3(x, op, ...) EXDEF2(x, op)
  7002. #define DEF2_WMS(x, op, ...) \
  7003. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7004. CompileAssert(!Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7005. #define DEF3_WMS(x, op, ...) DEF2_WMS(x, op)
  7006. #define EXDEF2_WMS(x, op, ...) \
  7007. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::HasMultiSizeLayout); \
  7008. CompileAssert(Js::OpCodeInfo<Js::OpCode::op>::IsExtendedOpcode);
  7009. #define EXDEF3_WMS(x, op, ...) EXDEF2_WMS(x, op)
  7010. #include "InterpreterHandler.inl"
  7011. // Make sure the macro and the layout for the op is consistent
  7012. #define DEF2(x, op, ...) \
  7013. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7014. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7015. #define DEF3(x, op, ...) DEF2(x, op)
  7016. #define DEF4(x, op, ...) DEF2(x, op)
  7017. #define EXDEF2(x, op, ...) \
  7018. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7019. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7020. #define EXDEF3(x, op, ...) EXDEF2(x, op)
  7021. #define EXDEF4(x, op, ...) EXDEF2(x, op)
  7022. #define DEF2_WMS(x, op, ...) \
  7023. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7024. CompileAssert(!Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7025. #define DEF3_WMS(x, op, ...) DEF2_WMS(x, op)
  7026. #define DEF4_WMS(x, op, ...) DEF2_WMS(x, op)
  7027. #define EXDEF2_WMS(x, op, ...) \
  7028. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::HasMultiSizeLayout); \
  7029. CompileAssert(Js::OpCodeInfoAsmJs<Js::OpCodeAsmJs::op>::IsExtendedOpcode);
  7030. #define EXDEF3_WMS(x, op, ...) EXDEF2_WMS(x, op)
  7031. #define EXDEF4_WMS(x, op, ...) EXDEF2_WMS(x, op)
  7032. #include "InterpreterHandlerAsmJs.inl"