InterpreterStackFrame.cpp 372 KB

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